从另一个类内部调用PHP类?
我正在构建小型MVC,有一些疑问需要解决 我有一个dispatcher类,这个类需要HTTP请求、HTTP响应和路由器类 我可以使用依赖项注入这样做:从另一个类内部调用PHP类?,php,oop,Php,Oop,我正在构建小型MVC,有一些疑问需要解决 我有一个dispatcher类,这个类需要HTTP请求、HTTP响应和路由器类 我可以使用依赖项注入这样做: $dispatcher = new Dispatcher($request, $response, $router); 现在让我们假设我不喜欢这种方法,并且希望在Dispatcher类中使用如下类: class Dispatcher() { protected $request; protected $response;
$dispatcher = new Dispatcher($request, $response, $router);
现在让我们假设我不喜欢这种方法,并且希望在Dispatcher类中使用如下类:
class Dispatcher()
{
protected $request;
protected $response;
protected $router;
public function __construct()
{
$this->request = new Request();
$this->response = new Response();
$this->router = new Router();
}
}
2方法是否有问题?我有没有违反OOP原则?还是这样使用就可以了?很难说一种方法或另一种方法有什么问题。只有不符合要求的规格才是错误的 第一种方法优于第二种方法的原因是,它允许您灵活地注入内容。例如:
class Dispatcher {
private $req;
public function __construct(IRequest $req) {
$this->req = $req;
}
}
interface IRequest {}
class Request implements IRequest {}
class MockRequest implements IRequest {}
//PRODUCTION
new Dispatcher(new Request);
//TESTING
new Dispatcher(new MockRequest);
您应该使用DI的原因如下:依赖项注入从代码中移除依赖项,并将它们抽象到调用方。这也使得对代码进行单元测试变得更容易,因为代码本身并不需要外部依赖才能正常工作 这在一个例子中得到了最好的证明。想象一下,如果您的类需要数据库连接:
class Dispatcher()
{
protected $db
public function __construct() {
$this->db = new MysqlDB();
}
}
现在,您只是强制所有人使用MySQL数据库。但是,如果使用DI,您可以抽象出数据库的细节,只需依赖于表示数据库对象的某个类:
class Dispatcher()
{
protected $db
public function __construct( Database $db) {
$this->db = $db;
}
}
然后,定义一些表示不同数据库连接的对象:
interface Database {
public function query( $sql);
}
class MySQLDB implements Database {
public function query( $sql) { // Stuff for MySQL
}
}
class OracleDB implements Database {
public function query( $sql) { // Stuff for Oracle
}
}
现在,您的用户是否:
$dispatcher = new Dispatcher( new MysqlDB());
或:
这没关系,同一个类可以在两个数据库中重用 第二个示例导致
Dispatcher
类和它使用的所有3个类之间紧密耦合。如果你正在寻找一个特定的法律或原则,这是违反了这一点,它将是
p.S.:您确定使用的是事件驱动架构吗?因为这是我唯一提到的
第二个示例应使用工厂后缀调用,因为它创建了其他对象 在这两个示例中,最终都会得到一个高度耦合的Dispatcher对象()
Dispatcher应该能够请求其他对象实现/注册到的接口或服务。为什么
Dispatcher
需要数据库实例?这就像把狗的腿钉在钉子上,然后叫它“章鱼”。难道不是类CRequest实现了IRequest{}
?和private$oReq代码>?为了使您的编码风格保持一致,tereško在界面符号的开头包含一个I
,这是一种常见的习惯用法,但它不会延续到其他定义。不,实际上这是一种常见的错误做法。接口不是“真正的抽象类”。接口是合同的定义,接口名称应描述所述合同的性质。而不是描述一个具体实现的类名。@tereško那么你会怎么称呼它呢?可请求?这取决于接口需要什么方法。
$dispatcher = new Dispatcher( new OracleDB());