Is there any way to redeclare a class safely in PH

2019-04-06 12:57发布

问题:

We all know the infamous "cannot redeclare class" error. Is there any method to overcome this and actually declare a new class with the same name, or is this impossible in PHP 5?

回答1:

As Pekka and Techpriester both pointed out: no, you cannot. However, if you're using PHP >= 5.3, then you can use namespaces and the "use" construct to effectively "redeclare" the class. Here's an example:

// MyClass.php
class MyClass {
  const MY_CONST = 1;
}
// MyNamespaceMyClass.php namespace Mynamespace; class MyClass { const MY_CONST = 2; }
// example.php require_once 'MyClass.php'; require_once 'MyNamespaceMyClass.php';
use Mynamespace\MyClass as MyClass;
echo MyClass::MY_CONST; // outputs 2

Thus, you've got your desired result, as MyClass now refers to your namespaced class.



回答2:

There may be a way using some obscure extension, but in basic standard PHP, as far as I know, no.

You can, however, always extend an existing class and - maybe, depending on your scenario - "smuggle" an instance of that extended class into the application you're working on.



回答3:

It is impossible. Depending on the use case, namespaces, like jpfuentes2 mentioned, might work for you.

One hack is to implement a custom new "operator".

Example:


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

class A {} $a = _new('A');

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

Another hack is to use runkit to re-implement a class.



回答4:

Perhaps a more modern answer for 2016, it looks like there are now at least 3 options:

Option 1. Using runkit

Ref: http://php.net/manual/en/function.runkit-class-emancipate.php

bool runkit_class_emancipate ( string $classname )

"Convert an inherited class to a base class, removes any method whose scope is ancestral"

Though I haven't tested this myself, it seems like a viable option if you have control over the extensions loaded. The drawback here would be that you lose all ancestral methods.


Option 2. Using runkit, again

Ref: 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 ] )

"Dynamically changes the code of the given method"

This solves the problem of option 1 if your goal is to tweak a method or two on the base class.


Option 3. Implement an Autoloader

Ref: http://php.net/manual/en/function.spl-autoload-register.php

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

"Register given function as __autoload() implementation"

This is personally my favorite of the 3, because:

  • It works natively in modern PHP versions
  • It can work in conjunction with other autoloaders
  • It allows you to implement conditional logic around your overrides

This is also one for which I do have some experience. An example implementation is as follows:

// 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';
  }
}


回答5:

AFAIK, redeclaring exiting functions or classes is not possible in PHP.

If you could tell, what you are trying to do, maybe there's another solution ...



回答6:

Basically you cannot redeclare a class. But if you really want to, you can. :) Everything is possible. Need a class, that changes it's structure dynamically? You can use magic method __call and pattern 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
  }

}

There is also a PHP toolkit to play with classes dynamically: http://php.net/manual/en/book.runkit.php

I know that redeclaring class and its methods is possible in Ruby (and I would consider it as a mistake in a language design).



回答7:

Basically we can't redeclare a class in PHP directly. If you are in need to get redeclare a class in php, then I suggest you to write that class in a separate file and use require_one to call that file to the desired page. It's as follows:

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

Now it will work as you desired. It worked for me.

The output will be as follows :

 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


标签: php oop class