Extension Methods
Extension methods provide syntactic sugar for two things:
- Helper methods you frequently call on a class/interface
- Extending functionality on classes/interfaces you do not "own"
Aphiria's extension method library helps you with the #1. For example, you may have an IList
interface that you frequently find yourself retrieving the first-or-default item from. Rather than have to extend the IList
interface to add this helper method, you can use an extension method to add it to the interface.
Note: Aphiria's implementation allows you to register extension methods on interfaces and/or parent classes, and "inherit" them in child classes.
The Gotcha
Unlike C#, PHP does not provide native functionality to dynamically add methods to a class without extending it. The closest thing we have is the magic method __call()
, which lets you specify what to do when an unknown method is called on an object. Aphiria's extension method library has one huge catch - you must have control over the classes you're extending. That does negate some of the advantages to real extension methods for sure, but they can still be useful when you're looking to extend classes' functionality from within your own projects without polluting the interfaces with these helper methods.
Basics
Let's expand upon the first-or-default example from above. You could do this statically via
class ListExtensions
{
public static function getFirstOrDefault(IList $list, mixed $default): mixed
{
return $list->count() === 0 ? $default : $list->get(0);
}
}
and use it via
$list = new ArrayList();
// Add stuff to the list...
$firstItem = ListExtensions::getFirstOrDefault($list, null);
There's nothing inherently wrong with this code, but it would be nice if we could call it like:
$list = new ArrayList();
// Add stuff to the list...
$firstItem = $list->getFirstOrDefault(null);
To do this with Aphiria, you must:
- Implement
Aphiria\ExtensionMethods\IExtendable
in your class or interface (IList
in this example)
- Use the
Aphiria\ExtensionMethods\ExtensionMethods
trait in your concrete class (ArrayList
in this example)
If you're using the full Aphiria framework, you can register the extension method in a module:
// $this in the closure will be rebound to an instance of IList
$this->withExtensionMethod(
$appBuilder,
IList::class,
'getFirstOrDefault',
fn (mixed $default): mixed => $this->count() === 0 ? $default : $this->get(0)
);
If you're not using the full framework and just wish to use the aphiria/extension-methods
package, you can register an extension method via:
ExtensionMethodRegistry::registerExtensionMethod(
IList::class,
'getFirstOrDefault',
fn (mixed $default): mixed => $this->count() === 0 ? $default : $this->get(0)
);
Net Library Extension Methods
Extension methods for the Net library can be enabled using a module:
$this->withNetExtensionMethods($appBuilder);
This will allow you to perform the logic within RequestParser
and ResponseFormatter
, but on IRequest
and IResponse
directly. The following extension methods are included:
// Body extension methods
IBody::getMimeType();
IBody::readAsFormInput();
IBody::readAsJson();
IBody::readAsMultipart();
// Header extension methods
Headers::isJson();
Headers::isMultipart();
Headers::parseContentTypeHeader();
Headers::parseParameters();
// Request extension methods
IRequest::getActualMimeType();
IRequest::getClientIPAddress();
IRequest::isJson();
IRequest::isMultipart();
IRequest::parseAcceptCharsetHeader();
IRequest::parseAcceptHeader();
IRequest::parseAcceptLanguageHeader();
IRequest::parseContentTypeHeader();
IRequest::parseCookies();
IRequest::parseParameters();
IRequest::parseQueryString();
IRequest::readAsFormInput();
IRequest::readAsJson();
IRequest::readAsMultipart();
// Response extension methods
IResponse::deleteCookie();
IResponse::setCookie();
IResponse::setCookies();
IResponse::redirectToUri();
IResponse::writeJson();
// URI extension methods
Uri::parseQueryString();
Closes #133