PHP и Runtime Subclassing / Переклассификация объектов - PullRequest
1 голос
/ 09 июля 2010

Базовая настройка. У меня есть экземпляр classA, который является подклассом classX ... При создании (или в другом месте) я хочу, чтобы он загрузил другой класс classB, который также является подклассом classX, и заменил себя на classB на месте. Вроде как фабрика, но та, которая заменяет себя прозрачно. При необходимости я могу обернуть classB с classA, если есть способ (во время выполнения) изменить подкласс объекта.

В настоящее время я использую classA::__call() для эмуляции магии MRO, но это выглядит очень не элегантно. Это необходимо сделать прозрачно для вызывающего classA/B, чтобы во внешнем мире он не знал, что classA заменил себя на classB после создания (или где-либо еще в этом отношении).

Я знаю, что при таких вещах PHP может быть немного тонким ... Я подозреваю, что мы не можем, но это было бы удобно для моей ситуации.

Кроме того, 5,3, но в идеале (чёрт) 5,2 / х

Заранее спасибо (желая, чтобы я писал на Python)

Ответы [ 2 ]

1 голос
/ 09 июля 2010

Хорошо, я заинтересовался этим вопросом, потому что достиг той точки, когда я хотел бы узнать точные пределы PHP, включая такие маленькие хаки. Надеюсь, я буду иметь смысл так поздно ночью и немного пива во мне. Из-за уродливого хакерства я действительно ожидаю, что меня отвергнут.

Очевидно, что вы не можете сделать $this = $that. Вы также не можете изменить глобальную переменную, которую вы сейчас пытаетесь превратить в объект, пока он создается, и попытка сделать это будет проигнорирована. Как Чарльз сказал ранее, это не может быть разумно сделано. Не с clone, не serialize(), ничего внутри __construct().

Таким образом, необоснованно, если вы хотите, чтобы $ a сначала стал объектом класса A, а затем преобразовать промежуточное создание в класс B, попробуйте этот псевдо-метод: вам придется вызывать __construct класса A два раза подряд. Первый раз обработать конструкцию класса A. Второй раз завершить объект, преобразовав его в класс B. Класс A обрабатывает первую половину конструкции, а класс B - вторую:


class A {

    function __construct() {
        $args = func_get_args();  // just to tell us the first round of __construct already occured
        if (array_key_exists(0, $args) AND $args[0]) {
            $GLOBALS['a'] = new B($GLOBALS['a']);
            // stop because "reconstruction" has stopped.  Nothing else you can do to $a in this scope.
            $this->aprop2 = "yay";
            // Seriously, stop.  Don't bother putting more code at this point, you're wasting your time.  Consider $a 'converted and returned' already.
            }
        // build on an object of class a here
        }
    }

class B {

    function __construct($var) {
        // maybe you'd like to do something with old $a?  If so, here's $var for you
        // continue constructing where A left off.
        }

    }


$a = new A(); // object of class A
$a->__construct(true);  // object of class B

Может быть, вместо этого сделать другой метод класса A с более важным звучанием, который делает то же самое для преобразования глобального $ a в объект класса B, просто чтобы он не выглядел так глупо, как мой пример. Другими словами, вы, вероятно, уже делаете это настолько хорошо, насколько позволяет PHP.

Редактировать: На самом деле вышеприведенное - не более чем $a = new A(); $a = new B($a);. Для лучшей читаемости и удобства сопровождения кода вы можете не использовать мой пример и вместо этого выбрать реализацию класса фабрики или обработчика, который создает и манипулирует этими объектами для вас. Я нашел краткую и проницательную статью www.ibm.com , объясняющую концепцию фабрик, как они применяются в PHP. Может быть концептуально, вам нужен статический класс, который действует как CD-чейнджер, и именно здесь Return by Reference - для работы с переменной ссылкой на объект в любой области видимости - и Variable Objects (см. комментарии midir на этой странице) - для динамической установки или работы с объектом - удобно.

1 голос
/ 09 июля 2010

В настоящее время это невозможно в PHP ...

Без всяких глупостей.

Если каждый экземпляр объекта является ссылкой, и эти ссылки могутбыть найденным в $GLOBALS, и объект знает, как называется каждый из этих экземпляров, вы могли бы заменить каждую ссылку на старый объект вашим новым объектом.Внешний мир не почувствует разницы.

Это, однако, потрясающе ужасная идея.Использование __call магия, вероятно, наименее безумный способ достижения вашей цели.

Редактировать: Всегда есть runkit , который позволит вам делать такие вещи, как добавление и удаление методов из классов.Однако это расширение PECL, которое может работать некорректно ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...