重新定义类方法或类

2022-08-30 10:10:51

有没有办法在不使用典型继承的情况下重新定义类或其某些方法?例如:

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年的历史了。

编辑:

我应该澄清,由于框架限制,我无法将类从重命名为 to 或其他任何内容。third_party_librarymagical_third_party_library

出于我的目的,是否可以只向类中添加一个函数?我认为你可以在C#中使用一种叫做“分部类”的东西来做到这一点。


答案 1

它被称为猴子补丁。但是,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\''
);

答案 2

runkit似乎是一个很好的解决方案,但它默认情况下未启用,并且其中一部分仍处于实验阶段。因此,我拼凑了一个小类,它替换了类文件中的函数定义。用法示例:

class Patch {

private $_code;

public function __construct($include_file = null) {
    if ( $include_file ) {
        $this->includeCode($include_file);
    }
}

public function setCode($code) {
    $this->_code = $code;
}

public function includeCode($path) {

    $fp = fopen($path,'r');
    $contents = fread($fp, filesize($path));
    $contents = str_replace('<?php','',$contents);
    $contents = str_replace('?>','',$contents);
    fclose($fp);        

    $this->setCode($contents);
}

function redefineFunction($new_function) {

    preg_match('/function (.+)\(/', $new_function, $aryMatches);
    $func_name = trim($aryMatches[1]);

    if ( preg_match('/((private|protected|public) function '.$func_name.'[\w\W\n]+?)(private|protected|public)/s', $this->_code, $aryMatches) ) {

        $search_code = $aryMatches[1];

        $new_code = str_replace($search_code, $new_function."\n\n", $this->_code);

        $this->setCode($new_code);

        return true;

    } else {

        return false;

    }

}

function getCode() {
    return $this->_code;
}
}

然后包括要修改的类并重新定义其方法:

$objPatch = new Patch('path_to_class_file.php');
$objPatch->redefineFunction("
    protected function foo(\$arg1, \$arg2)
    {   
        return \$arg1+\$arg2;
    }");

然后评估新代码:

eval($objPatch->getCode());

有点粗糙,但它有效!


推荐