php 重新定义类方法或类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/137006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:36:56  来源:igfitidea点击:

Redefine Class Methods or Class

phpclassmethodsredefine

提问by SeanDowney

Is there any way to redefine a class or some of its methods without using typical inheritance? For example:

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

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

What can I do to replace buggy_function()? Obviously this is what I would like to do

我能做些什么来代替buggy_function()?显然这是我想做的

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

This is my exact dilemma: I updated a third party library that breaks my code. I don't want to modify the library directly, as future updates could break the code again. I'm looking for a seamless way to replace the class method.

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

I've found this librarythat says it can do it, but I'm wary as it's 4 years old.

我发现这个图书馆说它可以做到,但我很谨慎,因为它已经有 4 年的历史了。

EDIT:

编辑:

I should have clarified that I cannot rename the class from third_party_libraryto magical_third_party_libraryor anything else because of framework limitations.

我应该澄清一下,由于框架限制,我不能将类重命名为third_party_librarytomagical_third_party_library或其他任何名称。

For my purposes, would it be possible to just add a function to the class? I think you can do this in C# with something called a "partial class."

就我而言,是否可以只向类添加一个函数?我认为您可以在 C# 中使用称为“部分类”的东西来做到这一点。

采纳答案by Jonathan Lonowski

It's called monkey patching. But, PHP doesn't have native support for it.

这叫做猴子修补。但是,PHP 没有对它的原生支持。

Though, as others have also pointed out, the runkit libraryis available for adding support to the language and is the successor to classkit. And, though it seemed to have been abandonedby its creator (having stated that it wasn't compatible with PHP 5.2 and later), the project does now appear to have a new home and maintainer.

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

I still can't say I'm a fanof its approach. Making modifications by evaluating strings of code has always seemed to me to be potentially hazardous and difficult to debug.

我仍然不能说我是它的方法的粉丝。在我看来,通过评估代码字符串进行修改总是具有潜在危险且难以调试。

Still, runkit_method_redefineappears to be what you're looking for, and an example of its use can be found in /tests/runkit_method_redefine.phptin the repository:

尽管如此,runkit_method_redefine似乎是您正在寻找的,并且可以/tests/runkit_method_redefine.phpt在存储库中找到其使用示例:

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

回答by JPhilly

runkit seems like a good solution but its not enabled by default and parts of it are still experimental. So I hacked together a small class which replaces function definitions in a class file. Example usage:

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;
}
}

Then include the class to be modified and redefine its methods:

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

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

Then eval the new code:

然后评估新代码:

eval($objPatch->getCode());

A little crude but it works!

有点粗糙,但它有效!

回答by Till

For the sake of completeness - monkey patching is available in PHP through runkit. For details, see runkit_method_redefine().

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

回答by Newbie

How about wrapping it in another class like

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

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);
 }
}

回答by Ludo - Off the record

For people that are still looking for this answer.

对于仍在寻找此答案的人。

You should use extendsin combination with namespaces.

您应该将extendsnamespaces结合使用。

like this:

像这样:

namespace MyCustomName;

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

Then to use it do like this:

然后像这样使用它:

use MyCustomName\third_party_library;

$test = new third_party_library();
$test->buggy_function();
//or static.
third_party_library::other_functions();

回答by Till

Yes, it's called extend:

是的,它被称为extend

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

I prefixed with "sd". ;-)

我以“sd”为前缀。;-)

Keep in mind that when you extend a class to override methods, the method's signature has to match the original. So for example if the original said buggy_function($foo, $bar), it has to match the parameters in the class extending it.

请记住,当您扩展一个类以覆盖方法时,该方法的签名必须与原始方法相匹配。因此,例如,如果原始说buggy_function($foo, $bar),它必须匹配扩展它的类中的参数。

PHP is pretty verbose about it.

PHP 对此非常详细。

回答by ólafur Waage

Zend Studio and PDT (eclipse based ide) have some built in refractoring tools. But there are no built in methods to do this.

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

Also you wouldn't want to have bad code in your system at all. Since it could be called upon by mistake.

此外,您根本不希望系统中有错误的代码。因为它可能会被错误地调用。

回答by Eric Lamb

There's alway extending the class with a new, proper, method and calling that class instead of the buggy one.

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

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

(Sorry for the crappy formatting)

(对不起,糟糕的格式)

回答by MOdMac

If the library is explicitly creating the bad class and not using a locater or dependency system you are out of luck. There is no way to override a method on another class unless you subclass. The solution might be to create a patch file that fixes the library, so you can upgrade the library and re-apply the patch to fix that specific method.

如果库显式地创建了坏类并且没有使用定位器或依赖系统,那么你就不走运了。除非您子类化,否则无法覆盖另一个类上的方法。解决方案可能是创建修复库的补丁文件,以便您可以升级库并重新应用补丁来修复该特定方法。

回答by Toxygene

You might be able to do this with runkit. http://php.net/runkit

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