【问题标题】:Static reference of a class object类对象的静态引用
【发布时间】:2014-09-01 20:55:21
【问题描述】:

我写了几个类,使用时都需要实例化。

我的目标是在尝试创建实例化类之间的动态访问时能够拥有完美的组织。

在一个类中,它会根据它刚刚所做的事情调用几个方法。这些方法之一将是来自其他类的方法。 (目前是静态方法)我会编辑这些行来控制类之间的行为。

我所说的动态是指,如果其中一个静态方法不可用或稍后可用,那么它只是执行不同的方法来在内部完成任务。

我的问题 是适当的 OOP 关注的问题。我不确定是否有更好的方法,或者我所做的是否会导致问题。虽然,它工作得很好。

我在下面准备了一个示例。其中,是表象,不是实际情况。 executionFileOne 是一种情况,ExecutingFileTwo 是另一种情况。

执行FileOne.php

require_once 'login.php';
$login = new Login();

require_once 'serverData.php';
$servDat = new serverData();

//blah blah blah

执行FileTwo.php

require_once 'serverData.php';
$servDat = new serverData();

//blah blah blah

登录.php

class Login {

    private static $thisClass = null;

    public function __construct(){
        //Get and set user data.
        self::setStaticClass($this);
    }

    public static function setStaticClass(&$inputClass){
        self::$thisClass = $inputClass;
    }

    //Methods Methods Methods

    //---Methods Executed by class at specific times---------------
    // - - - Used to get input from other classes

    //Methods Methods Methods

    //-------------------------------------------------------------

    //---Methods for other classes.--------------------------------
    // - - - Used to output data to other classes
    public static function getUserID(){
        die('Test'.self::$thisClass->userID);
    }

    //Methods Methods Methods of other classes.

    //-------------------------------------------------------------
}

服务器数据.php

class serverData {

    private static $thisClass = null;

    public function __construct(){
        //work work work
        //an IF statement detected needing to register userID on serverData
            $this->registerOnServer();
        //work work work
        self::setStaticClass($this);
    }

    //Methods Methods Methods

    public function registerOnServer(){
        //work work work
        $this->userID = $this->getUserID();
        //add userID to registration data.
    }

    //---Methods Executed by class at specific times---------------
    // - - - Used to get input from other classes
    private function getUserID(){
        if (class_exists('Login')) {
            return Login::getUserID();
        } else {
            return 0;
        }
    }
    //-------------------------------------------------------------

    //---Methods for other classes.--------------------------------
    // - - - Used to output data to other classes

    //Methods Methods Methods of other classes.

    //-------------------------------------------------------------
}

【问题讨论】:

  • 我不熟悉那个替代方案。
  • 我查了一下,但我的一个问题是,在特定情况下,并不是一直调用一个类。为了让它工作,我必须编辑数百页才能让它工作。如果我改变它,它会要求我编辑那一百个文件......我想。以 serverData 类需要 Login 类为例,但 Login 类并不总是可用的。
  • 啊,修复旧代码可能是一个挑战。这就是我从一开始就使用 DI/IoC 开始所有新项目的原因。无论如何,一个好的 IoC 容器也将支持 可选依赖项,或者可以使用 mock 依赖项(它满足 DI 要求,但实际上并没有“做”任何事情如果使用)- 重要的是提供了相同的接口(并且服务在上下文中按预期运行)。
  • 你能提供一个你描述的例子吗?我很难理解这种设计模式。
  • 我已经进一步澄清以表示它们是如何被调用的。另外,我仍然无法在这里建立联系。这种设计模式对我来说太离谱了。我希望给出一个由我制作的示例代码组成的示例,这将有助于我准确地了解您在说什么。

标签: php class oop reference static


【解决方案1】:

这是使用静态类时的几个问题之一,并且由于使用现场的偷偷摸摸的自注册和强耦合而变得更加复杂。目前我所知道的这个问题的“最佳”解决方案是使用依赖注入。

此外,在 DI 之上使用 IoC(控制反转)容器可以将所有内容连接在一起并管理生命周期成为一个合理的过程。 (不要恢复到 Service Locator 模式,除非在非常特殊的情况下,否则 DI+IoC 的美感会丢失!)

虽然非正式的鸭式“接口”就足够了,但使用编码接口有助于分类 - 并且通常(但不总是)需要 IoC 容器能够注册和解析组件。

// This is the service (interface) that different components will provider
inteface ILogin {
   public function getUserID ();
}

// Primary component (implementation) for the login service (interface)
class Login implements ILogin {
   // Note:
   // Constructor does NOT "register itself statically"; even when using
   // an approach similar to the original, use a proper Singleton Design.

   public function getUserID () { /* .. */ }
}

// Alternative/mock component (implementation) for the login service (interface)
class NoLogin implements ILogin {
   public function getUserID () { return 0; }
}

// Class (possibly also a component) that uses the login service dependency
class ServerData {
    // Constructor-based DI; the components are supplied as arguments
    // (There is also property-based DI.)
    public function __constructor(ILogin $login) {
        $this->login = $login;
    }

    // Later on we use the service
    // (It is a bit silly just to proxy the service, which should be
    //  injected elsewhere as required, but this mirrors the original.)
    public function getUserID () {
        // If not using a "mock service", then guard $this->login for null
        // because it is now an optional dependency; the appropriate approach
        // will vary based upon specific use-case.
        return $this->login->getUserID();
    }
}

后来:

// File 1-
// Note how dependency is "injected" into the server data
$servDat = new ServerData(new Login());

// File 2-
// A different dependency providing the same contract/service is used
$servDat = new ServerData(new NoLogin());
// Or, if ServerData guards usage and the service is "optional"
// $servDat = new ServerData(null);

所以这是核心 DI 的一种形式(虽然通用术语是 IoC,其中 DI 是一种实现) - 简单,但不是很令人兴奋,而且可能会变得乏味。此外,即使依赖项已被移到直接使用站点“外部”,它们仍然是消费者创建实例并手动注入组件的有效硬编码。

现在,DI+IoC 的魔力在哪里?组件被注册到 IoC 容器中,并且 IoC 容器用于实例化对象 - 这样的容器足够智能,可以自动解析 DI 依赖项。那么 File#1 和 File#2 之间的唯一区别是它们使用了稍微不同的 IoC 配置(一个使用 Login,另一个使用 NoLogin 用于 ILogin 服务)。

IoC 的其他有用功能是配置对象生命周期的能力。在这种情况下,登录组件(实现登录服务)可能是每个请求的实例,这实际上是“单例行为”——除了它不能在请求之间泄漏和,登录组件现在是松散的- 与 ServerData 类相结合。

IoC 容器还有很多 - 请参阅PHP DI,它似乎有一个相当不错的介绍。请注意,上面提供的 same DI 就绪代码可用于(在 PHP-DI 中)进行组件解析。 (错误是免费的。)

【讨论】:

  • 你有 21K 的声望,你甚至不费心输入昵称?
  • @bad_boy 也许我输入了“user2864740”:D(但实际上,我已经越来越喜欢这个数字了——就像第一个车牌一样。)
  • 好吧,反正不是很好……如果你只输入一个昵称,那么你会看起来更好。这是因为我们都看到用户的蹩脚问题和答案带有 1 个代表左右的随机数
  • 关于注解的有趣之处:r.je/php-annotations-are-an-abomination.html
  • @bad_boy 这是一本很好的读物,关于这种用法肯定有话要说——尽管大多数论点不适用于 DI 本身(PHP-DI 可以使用类型提示,如果作者认为这更好,我不知道)。但我真的是一个 C# 人,所以我查看了大多数这些论点并“pfft” - 但我对我的静态类型经验有很多偏见。
【解决方案2】:

我的一个朋友向我展示了一个比我更好的方法。可能不是正确的解决方案,但更好。

看到我实例化了我的类,并且可以通过全局调用变量来简单地访问其他类。而不是创建任何静态的东西。

例如:

require_once 'login.php';
$login = new Login();

require_once 'serverData.php';
$servDat = new serverData();

//blah blah blah


class Login {

    public function __construct(){
        //Get and set user data.
    }

    //Methods Methods Methods

    //---Methods Executed by class at specific times---------------
    // - - - Used to get input from other classes

    //Methods Methods Methods

    //-------------------------------------------------------------

    //---Methods for other classes.--------------------------------
    // - - - Used to output data to other classes
    public static function getUserID(){
        die('Test'.$this->userID);
    }
    //-------------------------------------------------------------
}

class serverData {

    public function __construct(){
        //work work work
        //an IF statement detected needing to register userID on serverData
            $this->registerOnServer();
        //work work work
    }

    //Methods Methods Methods

    public function registerOnServer(){
        //work work work
        $this->userID = $this->getUserID();
        //add userID to registration data.
    }

    //---Methods Executed by class at specific times---------------
    // - - - Used to get input from other classes
    private function getUserID(){
        global $login;
        if ($login != null) {
            return $login->getUserID();
        } else {
            return 0;
        }
    }
    //-------------------------------------------------------------

    //---Methods for other classes.--------------------------------
    // - - - Used to output data to other classes

    //Methods Methods Methods

    //-------------------------------------------------------------
}

【讨论】:

    猜你喜欢
    • 2015-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多