Есть ли способ переопределить класс безопасно в PHP? - PullRequest
8 голосов
/ 17 апреля 2010

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

Ответы [ 7 ]

14 голосов
/ 17 апреля 2010

Как указали Пекка и Техпристер: нет, вы не можете. Однако, если вы используете PHP> = 5.3, вы можете использовать пространства имен и конструкцию «use» для эффективного «переобъявления» класса. Вот пример: // MyClass.php class MyClass { const MY_CONST = 1; }<br> // MyNamespaceMyClass.php namespace Mynamespace; class MyClass { const MY_CONST = 2; }<br> // example.php require_once 'MyClass.php'; require_once 'MyNamespaceMyClass.php';<br> use Mynamespace\MyClass as MyClass;<br> echo MyClass::MY_CONST; // outputs 2

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

6 голосов
/ 17 апреля 2010

Может быть способ использовать какое-то неясное расширение, но в базовом стандартном PHP, насколько я знаю, нет.

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

2 голосов
/ 12 октября 2016

Возможно, более современный ответ на 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';
  }
}
2 голосов
/ 17 апреля 2010

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

Один из способов - реализовать новый пользовательский "оператор".

Пример:

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

<p>class A {}
$a = _new('A');</p>

<p>// change the implementation
$GLOBALS['class_map']['A'] = 'B';
$a2 = _new('A');

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

1 голос
/ 17 апреля 2010

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

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

0 голосов
/ 13 апреля 2014

По сути, мы не можем переопределить класс в PHP directly. Если вам нужно переопределить класс в 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();
}

Теперь все будет работать так, как вам нужно . Это сработало для me .

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

 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
0 голосов
/ 23 апреля 2010

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

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

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

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