PHP: Wrap all functions of a class in a subclass

2020-06-03 03:48发布

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...

4条回答
劫难
2楼-- · 2020-06-03 04:28

you might be looking for the decorator pattern:

class A
{
   function do1(){

   }
}
class DecoratorForA extends A
{
   private A original;
   public DecoratorForA( A original )
   {
      this.original = original;
   }
   function do1(){  //<-- override keyword in php?
      stuffBefore(); 
      original->do1();
      stuffAfter();      
   }
}

since this is not what you want, maybe this link is of help? http://code.google.com/p/php-aop/

查看更多
孤傲高冷的网名
3楼-- · 2020-06-03 04:33

If I understand you right, you want to extend a class, but not allow any of methods from the parent to be called. Instead, you want to call all of the methods yourself in one method in the new class.

So why do you even want to inherit in the first place? It sounds a lot like you should just create an adapter/decorator for your BaseClass.

class SubClass
{
   function magicalOverrideEveryone()
   {
      BaseClass bc = new BaseClass();
      bc.do_something();
      bc.do_something_else();
   }
}
查看更多
何必那么认真
4楼-- · 2020-06-03 04:39

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.

查看更多
家丑人穷心不美
5楼-- · 2020-06-03 04:39

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.

查看更多
登录 后发表回答