我已经在OOP上阅读了一段时间了,而且总是让我感到困惑,但我正在努力提高自己的技能(尽管我还是开始这样做,所以请善待)。
我正在设计一个主应用程序,其“核心”类是$App
。我的想法是,在应用程序的任何位置,您都可以在$App
内完成所有操作。
例如,我有一个$Db
类来查询数据库,$Mail
类用于发送电子邮件等。这些都是使用spl_autoload_register
自动加载的。
我的问题是关于实际正确实例化它们。以下是我现在正在做的事情:
的index.php
require_once('config.php'); // Autoloads classes and some other small stuff
$App = new App;
echo $App->Visitor->getIP();
App.class.php
class App {
public function __construct() {
$this->initialize();
}
private function initialize() {
$this->Visitor = new Visitor($this);
$this->Db = new Db($this);
$this->Mail = new Mail($this);
}
// Then some public methods...
// We are able to use $this->Visitor, $this->Db, etc...
}
Visitor.class.php
class Visitor {
private $App;
public function __construct($App) {
$this->App = $App; // I need access to all of App's methods
}
public function getIP() {
return $_SERVER['REMOTE_ADDR'];
}
}
所以上面的简短示例显示了我在所有课程中的表现。 App
类总是在它的构造函数中创建我们将在整个应用程序中使用的任何类的实例。
“child”类所有[dependency injects?] $App
实例,以便他们可以使用它的方法。
我这样做是否正确?它有效,但我不知道是否有更有效/更好的实践方法。
答案 0 :(得分:1)
在实例化时注入基类的问题在于它会使所有类都具有非常不明确的依赖关系。你的Visitor
类可以依赖于一个解析$_SERVER
超全局的类,但我不能仅仅通过查看它,它只是依赖是整个app对象。
最好只定义一个类所需的特定依赖项(通常在构造函数中),并创建一些正确提供这些依赖项的工作。这是你所暗示的“依赖注入”,它们通常涉及一些Container
,它存储已经实例化的所有对象,准备注入新类。
因此,您的应用将具有容器的依赖关系:
$app = new App(new Container);
然后你可以向容器询问依赖关系
class App {
/**
* @return App\Visitor
*/
public function getVisitor()
{
if (!$this->visitor) {
$this->visitor = $this->container->get('App\Visitor');
}
return $this->visitor;
}
}
如果你使用第三方依赖注入库(推荐 - 即使在开始设计你自己的时候也是一点切线),那么库通常会提供一些自动解决依赖关系的方法。它可以查看类上的构造函数(正确地打字,例如__construct(Visitor $visitor)
)并自动为构造函数提供参数 - 使用Reflection SPL
我还建议,如果你开始使用OOP,那么首先要熟悉PSR-4和Composer autoloading,因为手动包含所有课程将变得相当麻烦,并且正在做它是一开始的“标准”方式,将来当你想要切换时,生活会更轻松;)。