【问题标题】:Redefining PHP class functions on the fly?重新定义 PHP 类函数?
【发布时间】:2015-10-07 17:09:30
【问题描述】:

我试图弄清楚如何即时导入大量 PHP 类函数。比如……

class Entity
{
    public function __construct($type)
    {
    require_once $type."_functions.php"
    }

    // ...

}

$person = new Entity("human");
$person->sayhi();
$cow = new Entity("cow");
$cow->sayhi();

human_functions.php:

class Entity redefines Entity
    {
    public function sayhi()
        {
        echo "Hello world!";
        }
    }

cow_functions.php:

class Entity redefines Entity
    {
    public function sayhi()
        {
        echo "Moo!";
        }
    }

我发现了一些可能性,例如classkit_method_redefine()runkit_method_redefine()(它们是“实验性的”,无论如何它们都无法修改当前正在运行的类)。我现在使用的是 PHP 5.3.3,所以我不能使用Traits(不确定这是否是我正在寻找的东西)。我已经成功地重新定义了处理程序变量,如下所示:

// Example 2:
class OtherEntity { /* Code Here */ }
class Entity
    {
    public function __construct($type)
        {
        global $foo;
        unset($foo);
        $foo = new OtherEntity();
        }
    }

$foo = new Entity();

但是,这感觉就像一个 非常 hacky 方法。更重要的是,如果我不命名类$foo每个 实例,那么它将不起作用。我正在尝试做的事情有什么解决方法吗?

注意:我知道我可以扩展一个类,但在我的情况下,当启动 Entity 类时,没有安全的方法可以提前知道它需要启动哪个子类和。或许有一种方法我可以写,比如:

public function changeClass
    {
    this->class = OtherEntity;
    }

感谢您的帮助!

【问题讨论】:

  • 对于您的实际问题,肯定有另一种解决方案。您的第一个示例建议使用 factory pattern,但我不确定您真正想要实现的目标。
  • 是的,您做出了一些需要重新考虑的设计选择。
  • redefine 一个实际的 php 函数。我相信你在找extends
  • @CodeGodie 不,它不是,它是为了示例目的
  • 我能理解。接受的答案非常适合这种情况。 :)

标签: php oop


【解决方案1】:

这是您可以尝试的可能解决方案的想法。让CowHuman 类扩展Entity 类。但是,Entity 类将使用 factory 根据值是否安全来实例化对象。让我们更详细地看一下:

/*
 * Class Entity should not be able to be instantiated.
 * It should contain a factory to instantiate the
 * appropriate entity and an abstract function declaring 
 * the method that each entity will need to implement.
 */
abstract class Entity {

    public static function factory($type) {
        return (is_subclass_of($type, "Entity")) ? new $type() : FALSE;
    }

    abstract public function sayHi();

}

/*
 * Human class extends Entity and implements the
 * abstract method from Entity.
 */
class Human extends Entity {

    public function sayHi() {
        echo "Hello World!";
    }

}

/*
 * Cow class extends Entity and implements the
 * abstract method from Entity.
 */
class Cow extends Entity {

    public function sayHi() {
        echo "Moo!";
    }

}

现在要使用这个方法,调用工厂方法,如果一切正常,它将实例化适当的类,该类将扩展Entity

$person = Entity::factory("Human");
$person->sayHi();

$cow = Entity::factory("Cow");
$cow->sayHi();

使用is_subclass_of() 可以保证您的安全,因为如果传入的值不是扩展Entity 的类,您将返回FALSE 的值。

如果您想查看上面的代码,请复制上面的 php 代码并在 phpfiddle.org 上进行测试。

【讨论】:

  • 你就是那个男人。谢谢!这正是我一直在寻找的。为什么要抽象定义sayHi(); 函数?即使它没有在原始的Entity 类中定义,它似乎也能工作..
  • @DarthCaniac 没错。绝对会的。 abstract 关键字的好处是强制任何使用abstract function 扩展基类的类在它们自己的类中实现该方法。换句话说,HumanCow 都必须实现 sayHi() 否则 php 解释器会抛出错误。这保证了任何扩展 Entity 的类都将包含一个有效的 sayHi() 方法,该方法可以为该类做一些特定的事情。
  • 非常抱歉。此评论是为操作而设计的。移动沙发很烂,哈哈。
  • 哈哈,不用担心。我想的也差不多。只是想看看你是否有推荐的编辑。
  • 其实,你的建议是我无论如何都会做的。抽象类就是为此而生的。我会投票谢谢:)
【解决方案2】:

您可以做的一件事是创建HumanCow 作为Entity 的子类。当您执行new Entity("Human") 时,您可以在Entity 实例存储一个新创建的Human 对象。

然后您可以使用__call 将方法调用重定向到“子元素”。

class Entity{
    private $child;

    public function __construct($type){
        $this->child = new $type;
    }

    public function __call($func, $params=array()){
        $method = method_exists($this, $func)
            ? [$this, $func] : [$this->child, $func];
        return call_user_func_array($method, $params);
    }
}

class Human extends Entity{
    public function __construct(){}

    public function sayhi(){
        echo "Hello world!";
    }
}

class Cow extends Entity{
    public function __construct(){}

    public function sayhi(){    
        echo "Moo!";
    }
}

$person = new Entity("Human");
$person->sayhi();

$cow = new Entity("Cow");
$cow->sayhi();

唯一的缺点是$person$cow 都是Entity 对象。

【讨论】:

猜你喜欢
  • 2011-02-08
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 2011-06-20
  • 2011-10-19
  • 1970-01-01
相关资源
最近更新 更多