我们都知道臭名昭著的“无法重新声明类”错误。有没有什么方法可以克服这个问题并实际声明一个同名的新类,或者这在 PHP 5 中是不可能的吗?
正如 Pekka 和 Techpriester 都指出的那样:不,你不能。但是,如果您使用 PHP >= 5.3,那么您可以使用 namespaces 和“use”构造来有效地“重新声明”该类。这是一个例子:
// 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
因此,您已经得到了想要的结果,因为 MyClass 现在引用您的命名空间类。
可能有一种方法可以使用一些晦涩的扩展,但在基本标准 PHP 中,据我所知,没有。
但是,您始终可以扩展现有类,并且 - 也许根据您的情况 - 将该扩展类的实例“走私”到您正在处理的应用程序中。
注意:除自动加载器外的所有链接均参考 php 5 文档,不再有效。
也许是 2016 年更现代的答案,看起来现在至少有 3 个选择:
参考:http://php.net/manual/en/function.runkit-class-emancipate.php
bool runkit_class_emancipate ( string $classname )
“将继承类转换为基类,删除作用域为祖先的任何方法”
虽然我自己没有测试过,但如果您可以控制加载的扩展,这似乎是一个可行的选择。这里的缺点是你会失去所有祖先的方法。
参考: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 的问题。
参考:https://php.net/manual/en/function.spl-autoload-register.php
bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )
“将给定函数注册为 __autoload() 实现”
这是我个人最喜欢的三个,因为:
这也是我确实有一些经验的。示例实现如下:
// 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';
}
}
这是不可能的。根据用例,命名空间(如提到的 jpfuentes2)可能适合您。
一个技巧是实现一个自定义的新“运算符”。
示例:
$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');
另一个技巧是使用 runkit 重新实现一个类。
AFAIK,在 PHP 中重新声明现有函数或类是不可能的。
如果你能知道你正在尝试做什么,也许还有另一种解决方案......
基本上你不能重新声明一个类。但如果你真的想,你可以。 :) 一切皆有可能。需要一个类来动态地改变它的结构吗?您可以使用魔术方法 __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 中重新声明类及其方法是可能的(我认为这是语言设计中的一个错误)。
基本上我们不能在 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();
}
现在它将按您的意愿工作。它对我有用。
输出如下:
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