PHP:如何让spl_autoload在全局范围内的类中工作


PHP: How can I get spl_autoload to work within a class on the global scope?

我使用spl_autoload进行依赖项注入。

spl_autoload_register(function ($class)
{
    $cFilePath = _CLASSLIB_ . "/class.$class.php";
    if(file_exists($cFilePath))
    {
        include($cFilePath);
    }
    else
    {
        die("Unable to include the $class class.");
    }
});

这很好用。然而,假设这些是我的类:

class Test 
{ 
   public function foo() 
   { 
      echo "Here."; 
   } 
}  

class OtherTest 
{ 
   public function bar() 
   { 
      global $Test; 
      $Test->foo(); 
   } 
}  

所以,在我的执行代码中:

<?php
$OT = new OtherTest(); //Dependency Injection works and loads the file.
$OT->bar();
?>

我会得到一个错误,因为bar()试图在测试类中全局化(它没有实例化,因此从未自动加载)。

除了在尝试在每个方法中使用$Test全局对象之前检查它是否是对象之外,实现这一点的最佳方法是什么?

尽可能避免使用全局变量。您在评论中提到了依赖注入:您可以使用DI来解决这个问题。

如果OtherTest依赖于Test的一个实例,则在构建该实例时,应将该实例提供给OtherTest,例如

$T = new OtherTest($Test);

很明显,您需要修改OtherTest类,以使Test的实例作为属性,并使构造函数将Test作为参数,类似于:

class OtherTest 
{
    protected $test = null;
    public function __construct(Test $test)
    {
        $this->test = $test;
    }
    public function bar()
    {
        return $this->test->foo();
    }
}

然后您可以执行以下操作:

$test = new Test();
$otherTest = new OtherTest($test);
$otherTest->bar();

我认为您混淆了依赖注入的含义。类自动加载不是依赖项注入。依赖项注入是指将对象可能具有的依赖项实际注入到对象中,以便它可以与之一起工作。因此,接收依赖项的对象根本不需要创建其依赖项。

在这种情况下,实现依赖项注入的最佳方法是将对Test类的依赖项实际注入到对OtherTest的OtherTest实例化中。所以其他人可能是这样的:

class OtherTest 
{ 
   protected $test_object = NULL;
   public function __construct($test_obj) {
      if ($test_obj instanceof Test === false) {
          throw new Exception('I need a Test object');
      } 
      $this->test_obj = $test_obj;
   }
   public function bar() 
   { 
      $this->$test_obj->foo(); 
   } 
}

要实例化的代码可能看起来像:

$OT = new OtherTest(new Test()); // both OtherTest and Test would be autoloaded here if not previously loaded.

请注意,引用未声明的变量(示例中为$Test)不会自动加载类,因为变量名称本身没有类的上下文。在尝试调用非对象上的方法时,您只会得到一个错误。