PHP: обернуть все функции класса в подкласс - PullRequest
10 голосов
/ 02 марта 2012

Работая с классом библиотеки PHP, и я хотел бы обернуть все его публичные функции в подкласс ... Что-то вроде:

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

Свернув его, я быпредпочитайте не переопределять каждый метод суперкласса одним и тем же кодом-оберткой, если есть [несколько элегантный / чистый] способ сделать все это в одном месте.

Возможно ли это?Я подозреваю, что я нахожусь в стране метапрограммирования, и даже не знаю, предлагает ли PHP такого зверя, но решил, что я спрошу ...

Ответы [ 4 ]

20 голосов
/ 02 марта 2012

Вы можете легко сделать это с помощью __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();

Вы, конечно, захотите добавить немного обработки ошибок, например, запросить прокси-объект, отвечает ли он на данныйметод в __call и выдача ошибки, если это не так.Вы даже можете создать класс Proxy, который будет базовым классом для других прокси.Дочерние прокси-классы могут реализовывать before и after методы.

Недостатком является то, что ваш «дочерний класс» больше не реализует BaseClass, то есть, если вы используете type-hinting и хотят требовать, чтобы в функцию передавались только объекты типа BaseClass, этот подход потерпит неудачу.

2 голосов
/ 02 марта 2012

Если имена методов SubClass могут незначительно отличаться от исходных имен методов BaseClass, вы можете написать обобщенную оболочку с __call().Если имена методов должны совпадать, я не вижу, как вы могли бы достичь своей цели, не переписывая каждый метод вручную.Может быть, вы могли бы использовать funcall PECL , чтобы сделать это - но вы должны быть в состоянии загрузить этот PECL в первую очередь.

Если вы можете сделать методы BaseClass protected, подход __call() в подклассе будет работать.

Если вам не нужно для расширения класса, подход @ meager отлично подойдет.Обратите внимание, что __call () и call_user_func_array () накладывают определенные накладные расходы.

0 голосов
/ 02 марта 2012

Если я вас правильно понимаю, вы хотите расширить класс, но не разрешить вызов любого из методов родительского класса. Вместо этого вы хотите сами вызывать все методы в одном методе нового класса.

Так почему же вы вообще хотите наследовать? Это звучит так, будто вам нужно просто создать адаптер / декоратор для вашего BaseClass.

class SubClass
{
   function magicalOverrideEveryone()
   {
      BaseClass bc = new BaseClass();
      bc.do_something();
      bc.do_something_else();
   }
}
0 голосов
/ 02 марта 2012

Возможно, вы ищете шаблон декоратора:

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();      
   }
}

, поскольку это не то, что вы хотите, может быть, эта ссылка поможет?http://code.google.com/p/php-aop/

...