繁体   English   中英

静态/非静态方法问题

[英]Static / Non-Static Method Issue

我正在研究一个简单的ORM解决方案,并遇到了棘手的情况。 理想情况下,我希望能够在静态上下文和对象上下文中使用方法,具体取决于它的调用方式。 我不确定这是否可行,但这就是我的意思:

假设用户模型想静态调用where(),这当前工作正常,例如:

$user = User::where('id = ?', 3);

现在,我也支持关系,例如用户可以拥有消息。 建立此关系后,我只需在用户模型中存储消息模型的空白副本并设置外键。 例如:

$user -> messages = new Message();
$user -> messages -> foreign_key = 'user_id';

现在,理想情况下,我希望能够致电:

$user -> messages -> where('unread = ?', 1);

在非静态上下文中,在此上下文中使用$ this - > foreign_key,以便仅提取外键与用户id匹配的消息。 这种类型的上下文切换在PHP中是否可行? 从静态上下文对$ this的任何引用都会抛出一个错误,因为它是一个静态方法,并且不应该依赖于$ this(出于显而易见的原因,当从静态上下文调用时,$ this将不存在)

这有什么巧妙的方法吗? 我尝试重载方法有两个不同的原型,有和没有静态关键字,但这引发了重新声明错误。

经过相当多的游戏后,我找到了一种方法,可以在没有@ drew010提到的Strict Standards错误的情况下使其可行。 我不喜欢它,它感觉很糟糕,但它确实有效,所以无论如何我都会发布。

基本上,我们的想法是让您想要访问的方法是privatestatic 然后定义__call()__callStatic()魔术方法,以便它们调用私有静态方法。 现在你可能会认为“这不能解决问题,我仍然停留在一个静态上下文中” - 你只是为了一个小的补充,你可以将$this附加到传递给__call()实际方法的参数并将其作为方法的最后一个参数获取。 因此,不是在对象上下文中引用$this ,而是引用第三个参数来获取对自己实例的引用。

我可能不会很好地解释这个,只看看这段代码

<?php

class test_class {

    private $instanceProperty = 'value';

    private static function where ($arg1, $arg2, $obj = NULL) {
        if (isset($obj)) {
            echo "I'm in an object context ($arg1, $arg2): I can access the instance variable: $obj->instanceProperty<br>\n";
        } else {
            echo "I'm in a static context ($arg1, $arg2)<br>\n";
        }
    }

    public function __call ($method, $args) {
        $method = "self::$method";
        if (is_callable($method)) {
            $args[] = $this;
            return call_user_func_array($method, $args);
        }
    }

    public static function __callStatic ($method, $args) {
        $method = "self::$method";
        if (is_callable($method)) {
            return call_user_func_array($method, $args);
        }
    }

}

test_class::where('unread = ?', 1);

$obj = new test_class();
$obj->where('unread = ?', 2);

如果不违反PHP标准并以不应该使用的方式使用语言,我想不出任何方法可以做到这一点。

函数是静态的还是非静态的。 是PHP允许您以任何方式调用它,但这确实违反了严格的标准,并且您可以逃避这样做的唯一原因是向后兼容旧的PHP 4代码,其中静态不作为关键字存在。

考虑以下代码:

<?php

class Test {
    protected $_userId;

    public function find()
    {
        if (isset($this)) {
            echo "Not static.<br />\n";
        } else {
            echo "Static.<br />\n";
        }
    }
}

$t = new Test();
$t->find();

Test::find();

输出是:

不是静止的。
静态的。

但是在启用错误报告的情况下,这是实际输出:

不是静止的。

严格标准:非静态方法Test :: find()不应在第19行的test.php中静态调用
静态的。

如果将方法声明为static,则无论调用哪种方式,它都是静态的。

所以我认为答案是肯定的,你可以使用这种解决方法,但我不推荐它。 如果你想两种方式,我建议添加两个方法, public function find()public static function findStatic()

由于你的代码要么写成$obj->find()Class::find() ,你可以在我看来轻松使用静态和非静态方法,而不是让一个方法静态地运行。 为了坚持DRY,我想一种方法可以利用另一种方法来进行实际发现。

很抱歉没有回答你的问题,但我有一些评论不适合...评论。 你正在做的事情有点不合逻辑。

$user->messages = new Message();

你要创建一个单一的消息中的变量称为消息
你的意思是$user->messages[] = new Message();
另外,保护您的类变量。

$user->messages->where('unread = ?', 1);

在这里,您尝试从用户消息中进行选择,这是无稽之谈。
你应该做的就像你对User类所做的一样:静态获取消息,然后将它们分配给你的用户:

$user->messages = Message::where('unread = ?', 1);

如果需要查找具有特定主键的消息,请将其作为参数传递给where方法,该方法可以增强以采用许多子句:

$messages = Message::where(array(
    array('unread = ?', 1),
    array('id = ?',     $message->getID()),
));

我还想添加一个个人注释:创建ORM是一种很好的学习方式,但如果你正在寻找更严肃的东西,我建议你给Doctrine或Propel看一看。

从理论和实践的角度来看,拥有一个可以从静态和非静态上下文中调用的类方法并不是一个好主意。

如果您希望在整个应用程序中实现类/方法的可访问性,那么阅读依赖注入,服务容器和依赖注入的编程可能是一个良好的开端。

通过在您的应用程序中实现DI,您很可能不再需要您提到的内容。

我建议调查低谷网络,你会发现你正在使用的上下文中的静态调用被避免并被标记为不好的做法。 面向对象编程中的静态/共享状态是应该避免的(以及单例模式)。

不要误解我的意思 - >静态方法有其目的和好处,但是,你使用它的方式有点过时(尽管一些框架,如Laravel,促进了这种不良做法 - 例如“Facades”和Eloquent)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM