Sea*_*ney 47 php methods class redefine
有没有办法在不使用典型继承的情况下重新定义类或其某些方法?例如:
class third_party_library {
function buggy_function() {
return 'bad result';
}
function other_functions(){
return 'blah';
}
}
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能取代buggy_function()?显然这就是我想做的
class third_party_library redefines third_party_library{
function buggy_function() {
return 'good result';
}
function other_functions(){
return 'blah';
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的两难:我更新了破坏我代码的第三方库.我不想直接修改库,因为将来的更新可能会再次破坏代码.我正在寻找一种无缝的方法来替换类方法.
我发现这个图书馆说它可以做到,但我很谨慎,因为它已经4岁了.
编辑:
我应该澄清一下,由于框架限制,我无法将类重命名third_party_library为magical_third_party_library或其他任何内容.
为了我的目的,是否可以只在类中添加一个函数?我认为你可以用C#做一个叫做"部分类"的东西.
Jon*_*ski 39
它被称为猴子修补.但是,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\''
);
Run Code Online (Sandbox Code Playgroud)
JPh*_*lly 14
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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后包括要修改的类并重新定义其方法:
$objPatch = new Patch('path_to_class_file.php');
$objPatch->redefineFunction("
protected function foo(\$arg1, \$arg2)
{
return \$arg1+\$arg2;
}");
Run Code Online (Sandbox Code Playgroud)
然后评估新代码:
eval($objPatch->getCode());
Run Code Online (Sandbox Code Playgroud)
有点原油,但它的工作原理!
小智 8
如何将它包装在另一个类中
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);
}
}
Run Code Online (Sandbox Code Playgroud)
对于那些仍在寻找这个答案的人.
像这样:
namespace MyCustomName;
class third_party_library extends \third_party_library {
function buggy_function() {
return 'good result';
}
function other_functions(){
return 'blah';
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用它做这样:
use MyCustomName\third_party_library;
$test = new third_party_library();
$test->buggy_function();
//or static.
third_party_library::other_functions();
Run Code Online (Sandbox Code Playgroud)
是的,它被称为extend:
<?php
class sd_third_party_library extends third_party_library
{
function buggy_function() {
return 'good result';
}
function other_functions(){
return 'blah';
}
}
Run Code Online (Sandbox Code Playgroud)
我以"sd"为前缀.;-)
请记住,当您扩展类以覆盖方法时,方法的签名必须与原始方法匹配.因此,例如,如果原始说buggy_function($foo, $bar),它必须匹配扩展它的类中的参数.
PHP非常冗长.