类对象的静态引用


Static reference of a class object

我已经编写了几个类,它们在使用时都需要实例化。

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

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

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

我的问题是适当OOP关注的问题。我不确定是否有更好的方法,或者我所做的事情是否会引起问题。尽管如此,它运行得很好。

下面我准备了一个例子。其中,是一种表述,而非实际情况。executingFileOne是一种情况,ExecutingFileTwo是另一种情况。

执行FileOne.php

require_once 'login.php';
$login = new Login();
require_once 'serverData.php';
$servDat = new serverData();
//blah blah blah

执行文件Two.php

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

login.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.
    //-------------------------------------------------------------
}

serverData.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.
    //-------------------------------------------------------------
}

这是使用静态类时的几个问题之一,由于使用站点上的自注册和强耦合,这一问题更加复杂。目前,我所知道的这个问题的"最佳"解决方案,也是我鼓励的解决方案,是使用依赖注入。

此外,在DI之上使用IoC(控制反转)容器可以将所有东西连接在一起,并管理寿命,这是一个合理的过程。(不要恢复到服务定位器模式,除非在非常特殊的情况下,或者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依赖关系。那么,文件#1和文件#2之间的唯一区别是,它们使用的IoC配置略有不同(一个使用Login,另一个使用NoLogin作为ILogin服务)。

IoC的另一个有用特性是配置对象生存期的能力。在这种情况下,Login组件(实现登录服务)可能是每个请求的实例,这实际上是"单例行为"——除了它不能在请求之间泄漏之外——Login组件现在与ServerData类松散耦合。

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

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

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

例如:

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