Есть ли способ безопасно переопределить класс в PHP?

Мы все знаем, что печально известная ошибка «не может переопределить класс». Есть ли способ преодолеть это и фактически объявить новый класс с тем же именем или это невозможно в PHP 5?

Related of "Есть ли способ безопасно переопределить класс в PHP?"

Как заметили Пекка и Техприртер, нет: вы не можете. Однако, если вы используете PHP> = 5.3, вы можете использовать пространства имен и конструкцию «использовать», чтобы эффективно «обновлять» класс. Вот пример:

 // MyClass.php
 класс MyClass {
   const MY_CONST = 1;
 } 
// MyNamespaceMyClass.php пространство имен Mynamespace; класс MyClass { const MY_CONST = 2; }
// example.php require_once 'MyClass.php'; require_once 'MyNamespaceMyClass.php';
используйте Mynamespace \ MyClass как MyClass;
echo MyClass :: MY_CONST; // выходы 2

Таким образом, у вас есть желаемый результат, так как MyClass теперь ссылается на ваш класс с именами.

Возможно, есть способ использования некоторого неясного расширения, но в базовом стандартном PHP, насколько мне известно, нет.

Тем не менее, вы всегда можете расширить существующий класс и, возможно, в зависимости от вашего сценария – «контрабандой» экземпляр этого расширенного класса в приложение, над которым вы работаете.

Это невозможно. В зависимости от используемого варианта пространства имен, например jpfuentes2, могут работать для вас.

Один взлом – это реализовать пользовательский новый «оператор».

Пример:

 $GLOBALS['class_map'] = array('A' => 'A'); function _new($class){ $realClass = $GLOBALS['class_map'][$class]; return new $realClass; } 

$GLOBALS['class_map'] = array('A' => 'A'); function _new($class){ $realClass = $GLOBALS['class_map'][$class]; return new $realClass; }

класс A {}
$ a = _new ('A');

// изменение реализации
$ GLOBALS ['class_map'] ['A'] = 'B';
$ a2 = _new ('A');

Другой взлом – использовать runkit для повторного внедрения класса.

Возможно, более современный ответ на 2016 год, похоже, сейчас есть как минимум 3 варианта:

Вариант 1. Использование runkit

Ссылка: http://php.net/manual/en/function.runkit-class-emancipate.php

bool runkit_class_emancipate ( string $classname )

«Преобразовать унаследованный класс в базовый класс, удаляет любой метод, объем которого является родовым»

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


Вариант 2. С помощью runkit снова

Ссылка: http://php.net/manual/en/function.runkit-method-redefine.php

bool runkit_method_redefine ( string $classname , string $methodname , string $args , string $code [, int $flags = RUNKIT_ACC_PUBLIC ] )

«Динамически изменяет код данного метода»

Это решает проблему варианта 1, если ваша цель – настроить метод или два в базовом классе.


Вариант 3. Внедрение автозагрузчика

Ссылка: http://php.net/manual/en/function.spl-autoload-register.php

bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )

«Зарегистрировать данную функцию как реализацию __autoload ()»

Это лично моя любимая из 3, потому что:

  • Он работает в современных версиях PHP
  • Он может работать совместно с другими автозагрузчиками
  • Это позволяет вам применять условную логику вокруг ваших переопределений

Это также тот, для которого у меня есть некоторый опыт. Пример реализации следующий:

 // Some early point in your application // Ideally after other autoloaders have registered spl_autoload_register('autoload_override'); function autoload_override($class) { if ($class == 'TargetClassName') { include '/path/to/overriding/class.php'; } } 

AFAIK, переопределение функций или классов исключений невозможно в PHP.

Если бы вы могли сказать, что вы пытаетесь сделать, может быть, есть другое решение …

В принципе, вы не можете переопределить класс. Но если вы действительно этого хотите, можете. 🙂 Все возможно. Нужен класс, который динамически меняет структуру? Вы можете использовать магический метод __call и состояние шаблона.

 class Example { var $state; public function setImplementation($state) { $this->state = $state; } public function __call($method, $args) { if (method_exists($this->state, $method)) return $this->state->$method($args); else // error } } 

Существует также набор инструментов PHP для динамического воспроизведения классов: http://php.net/manual/en/book.runkit.php

Я знаю, что класс Rubeclaring и его методы возможны в Ruby (и я считаю это ошибкой в ​​дизайне языка).

В принципе, мы не можем переопределять класс в PHP directly . Если вам нужно получить redeclare класс в php, я предлагаю вам написать этот класс в отдельном файле и использовать require_one для вызова этого файла на нужную страницу. Это выглядит так:

page1.php

 class abcd { function max() { echo "Hello World!!! count:-".$GLOBALS['x']; } } 

page2.php

 $i=10; for($x=0;$x<$i;$x++) { require_once "Page1.php"; $myclass = new abcd(); $myclass->max(); } 

Теперь он будет работать по вашему желанию . Это сработало для меня .

Выход будет следующим:

  Hello World!!! count:- 0 Hello World!!! count:- 1 Hello World!!! count:- 2 Hello World!!! count:- 3 Hello World!!! count:- 4 Hello World!!! count:- 5 Hello World!!! count:- 6 Hello World!!! count:- 7 Hello World!!! count:- 8 Hello World!!! count:- 9