有什么方法可以在 PHP 中安全地重新声明类吗?

问题描述 投票:0回答:7

我们都知道臭名昭著的“无法重新声明类”错误。有没有什么方法可以克服这个问题并实际声明一个同名的新类,或者这在 PHP 5 中是不可能的吗?

php oop class
7个回答
14
投票

正如 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 现在引用您的命名空间类。


5
投票

可能有一种方法可以使用一些晦涩的扩展,但在基本标准 PHP 中,据我所知,没有。

但是,您始终可以扩展现有类,并且 - 也许根据您的情况 - 将该扩展类的实例“走私”到您正在处理的应用程序中。


3
投票

注意:除自动加载器外的所有链接均参考 php 5 文档,不再有效。

也许是 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.实施自动加载器

参考:https://php.net/manual/en/function.spl-autoload-register.php

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

“将给定函数注册为 __autoload() 实现”

这是我个人最喜欢的三个,因为:

  • 它可以在现代 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
投票

这是不可能的。根据用例,命名空间(如提到的 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 重新实现一个类。


1
投票

AFAIK,在 PHP 中重新声明现有函数或类是不可能的。

如果你能知道你正在尝试做什么,也许还有另一种解决方案......


0
投票

基本上你不能重新声明一个类。但如果你真的想,你可以。 :) 一切皆有可能。需要一个类来动态地改变它的结构吗?您可以使用魔术方法 __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 中重新声明类及其方法是可能的(我认为这是语言设计中的一个错误)。


0
投票

基本上我们不能在 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
© www.soinside.com 2019 - 2024. All rights reserved.