重新定义类方法或者类

时间:2020-03-06 14:45:29  来源:igfitidea点击:

是否有任何方法可以在不使用典型继承的情况下重新定义类或者其某些方法?例如:

class third_party_library {
    function buggy_function() {
        return 'bad result';
    }
    function other_functions(){
        return 'blah';
    }
}

我该怎么做才能替换buggy_function()?显然这是我想做的

class third_party_library redefines third_party_library{
    function buggy_function() {
        return 'good result';
    }
    function other_functions(){
        return 'blah';
    }
}

这是我的两难选择:我更新了破坏我的代码的第三方库。我不想直接修改该库,因为将来的更新可能会再次破坏代码。我正在寻找一种无缝的方法来替换类方法。

我发现这个库说可以做到,但是我很警惕,因为它已经有4年的历史了。

编辑:

我应该澄清的是,由于框架的限制,我无法将类从" third_party_library"重命名为" magical_third_party_library"或者其他任何名称。

就我的目的而言,是否可以仅将一个函数添加到类中?我认为我们可以在C中使用称为"局部类"的方法来完成此操作。

解决方案

Zend Studio和PDT(基于Eclipse的ide)具有一些内置的折射工具。但是没有内置的方法可以做到这一点。

同样,我们根本不想在系统中使用任何错误的代码。因为它可能被错误地调用。

这就是所谓的猴子修补。但是,PHP没有本机支持。

但是,正如其他人也指出的那样,runkit库可用于添加对该语言的支持,并且是classkit的后继者。并且,尽管它似乎已被其创建者放弃(已经声明它与PHP 5.2及更高版本不兼容),但该项目现在似乎有了新的家和维护者。

我仍然不能说我喜欢它的方法。在我看来,通过评估代码字符串进行修改似乎始终具有潜在的危险并且难以调试。

尽管如此,runkit_method_redefine似乎仍然是我们要寻找的东西,它的用法示例可以在存储库中的/ tests / runkit_method_redefine.phpt中找到:

runkit_method_redefine('third_party_library', 'buggy_function', '',
    'return \'good result\''
);

是的,它称为extend

<?php
class sd_third_party_library extends third_party_library
{
    function buggy_function() {
        return 'good result';
    }
    function other_functions(){
        return 'blah';
    }
}

我以" sd"为前缀。 ;-)

请记住,当我们扩展类以覆盖方法时,方法的签名必须与原始签名匹配。因此,例如,如果原始名称为buggy_function($ foo,$ bar),则必须匹配扩展它的类中的参数。

PHP非常详细。

总是用一种新的,适当的方法扩展该类,并调用该类而不是有缺陷的类。

class my_better_class Extends some_buggy_class {
    function non_buggy_function() {
        return 'good result';
    }
}

(对不起的格式化)

如果该库显式创建坏类,而不使用定位器或者依赖项系统,那么我们很不走运。除非我们有子类,否则无法覆盖另一个类上的方法。
解决方案可能是创建一个修复该库的补丁文件,因此我们可以升级该库并重新应用该补丁以修复该特定方法。

我们也许可以使用runkit来做到这一点。 http://php.net/runkit

为了完整起见,猴子补丁可以通过runkit在PHP中使用。有关详细信息,请参见runkit_method_redefine()

如何将其包装在另一个类中

class Wrapper {
 private $third_party_library;
 function __construct() { $this->third_party_library = new Third_party_library(); }
 function __call($method, $args) {
  return call_user_func_array(array($this->third_party_library, $method), $args);
 }
}