有没有办法在不使用典型继承的情况下重新定义类或其某些方法?例如:
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#做一个叫做"部分类"的东西.
它被称为猴子修补.但是,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\''
);
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('','',$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());
有点原油,但它的工作原理!
为了完整起见 - 通过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); } }
对于那些仍在寻找这个答案的人.
您应该将extends与名称空间结合使用.
像这样:
namespace MyCustomName; class third_party_library extends \third_party_library { function buggy_function() { return 'good result'; } function other_functions(){ return 'blah'; } }
然后使用它做这样:
use MyCustomName\third_party_library; $test = new third_party_library(); $test->buggy_function(); //or static. third_party_library::other_functions();
是的,它被称为extend
:
我以"sd"为前缀.;-)
请记住,当您扩展类以覆盖方法时,方法的签名必须与原始方法匹配.因此,例如,如果原始说
buggy_function($foo, $bar)
,它必须匹配扩展它的类中的参数.PHP非常冗长.
那么答案是,你做不到.
OP询问如何"没有典型的继承".即他正在寻找类似Java的反思
这通常会起作用,但由于我正在使用的框架是如何设置的,我无法更改类名