Working with a PHP library class, and I'd like to wrap all of its public functions in a subclass... Something along the lines of:
class BaseClass
{
function do_something()
{
some;
stuff;
}
function do_something_else()
{
other;
stuff;
}
/*
* 20-or-so other functions here!
*/
}
class SubClass extends BaseClass
{
function magicalOverrideEveryone()
{
stuff-to-do-before; // i.e. Display header
call_original_function(); // i.e. Display otherwise-undecorated content
stuff-to-do-after; // i.e. Display footer
}
}
Boiling it down, I'd prefer not to have to override every superclass method with the same wrapper code, if there's a [somewhat elegant / clean] way to do it all in one place.
Is this possible? I suspect I'm in metaprogramming land here, and don't even know if PHP offers such a beast, but figured I'd ask...
In function overriding, both parent and child classes should have same function name with and number of arguments. It is used to replace parent method in child class. The purpose of overriding is to change the behavior of parent class method. The two methods with the same name and same parameter is called overriding.
You cannot overload PHP functions. Function signatures are based only on their names and do not include argument lists, so you cannot have two functions with the same name. Class method overloading is different in PHP than in many other languages.
Extending Classes And Overriding A class extends another by using the “extends” keyword in its declaration. If we wanted to extend WP_Query, we would start our class with “product_query extends WP_Query.” Any class can be extended unless it is declared with the final keyword.
You could do this easily with the __call
magic method and a generic "proxy" class which doesn't inherit directly from the base class.
Here is a (near) complete implementation of a proxying class which wraps whatever object you pass it. It will invoke some "before" and "after" code around each method call.
class MyProxy {
function __construct($object) {
$this->object = $object;
}
function __call($method, $args) {
// Run before code here
// Invoke original method on our proxied object
call_user_func_array(array($this->object, $method), $args);
// Run after code here
}
}
$base = new BaseClass();
$proxy = new MyProxy($base);
$proxy->doSomething(); // invoke $base->doSomething();
You would of course want to add a bit of error handling, like asking the proxied object if it responds to the given method in __call
and raising an error if it doesn't. You could even design the Proxy class to be a base-class for other proxies. The child proxy classes could implement before
and after
methods.
The downside is that your "child class" no longer implements BaseClass
, meaning if you're using type-hinting and want to demand that only objects of type BaseClass
are passed into a function, this approach will fail.
If the method names of SubClass may differ slightly from the original method names of BaseClass, you could write a generic wrapper with __call()
. If the method names must match, I don't see how you could achieve your goal without manually overwriting each method. Maybe you could use the funcall PECL to do this - but you'd have to be able to load that PECL in the first place.
If you can make the methods of BaseClass protected
, the __call()
approach in SubClass will work.
If you do not need to extend the class, @meager's approach is perfectly fine. Please note that __call() and call_user_func_array() do impose a certain overhead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With