DI 容器 - 正确的做法?
DI Container - correct way of doing it?
我有一长串依赖注入来显示包含文章、导航等的页面。目前我将它们放在一个名为 index.php 的文件中以将它们粘合在一起。
index.php,
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
use MyCustomVerndorName\Slug\Mapper\SlugMapper;
.... (more)
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Nav model.
$NavModel = new NavModel();
$NavMapper = new NavMapper($PdoAdapter);
$NavService->setMapper($NavMapper)->setModel($NavModel);
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
... (more)
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
... (more)
$NavChildrenComponent = new NavChildrenComponent($PdoAdapter);
... (more)
// Inject components.
$NavMapper->addComponent($NavChildrenComponent);
$NavMapper->addComponent($NavLanguageComponent);
// Controll the slug.
$SlugController->setService($SlugService)->fetchRow([
"url" => $url
]);
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
在我的 router.php 中(我正在使用 AltoRouter),
use AltoRouter as Router;
$Router = new Router();.
$Router->map('GET', '/', '/article/container');
... (and other routes)
if($match)
{
$target = $match['target'];
$url = isset($match['params']['url']) ? $match['params']['url'] : DEFAULT_HOMEPAGE;
$language = isset($match['params']['language']) ? $match['params']['language'] : null;
include __DIR__ . $target . '.php';
}
我正在考虑将 index.php 中的依赖项注入列表放入容器 class 以便我可以在需要时调用它 class,
例如 router.php、
$Router->map('GET', '/', 'MyCustomVerndorName\Article\Container\ArticleContainer');
....
new $target($PdoAdapter, $url, $language);
还有这个容器class,
namespace MyCustomVerndorName\Article\Container;
// Mapper.
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
...
class ArticleContainer
{
/*
* Construct dependency.
*/
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
// Slug.
$SlugService = new SlugService();
$SlugController = new SlugController();
// Nav.
$NavService = new NavService();
$NavController = new NavController();
// Article.
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
...
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
...
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
}
}
基本上,我把所有的依赖列表都放到了__construct
,
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
...
}
那么,这是做 DI 容器的正确方法,而不依赖 PHP 的众所周知的容器(例如 Pimple,Symfony\DependencyInjection, 等等)?
传统上,DI 容器returns 按需提供服务。您所说的 ArticleContainer 实际上只是一个函数,然后呈现一个视图。它做了很多 DI 注入,但它不是容器。
假设您有一个正确初始化的真实容器。您的代码如下所示:
$container = new Container();
// Some initialization
// Now use it
$viewArticle = $container->get('view_article');
echo $viewArticle->render('index.php');
希望您能看出其中的区别。初始化完成后,您的应用程序只需拉出它需要的视图并呈现它。无需担心 pdo 或 url 等
那么我们如何将我们的文章视图服务放入容器中呢?
$container = new Container();
// Some initialization
$container->set('page_template',function($container)
{
return new PageTemplate();
}
$container->set('article_view',function($container)
{
$articleView = new ArticleView(
$container->get('page_template',
$container->get('article_model')
);
$articleView->setSlug($container->get('slug_model');
$articleView->setNav ($container->get('nav_model');
return $articleView;
};
// Now use it
$viewArticle = $container->get('article_view');
echo $viewArticle->render('index.php');
所以我们为我们的容器定义了两个服务函数。当我们执行 $container->get('article_view'); 时,容器以容器本身作为参数调用该函数。该函数通过从容器中拉出依赖项然后 returns 新对象来创建所需的 class。
假设您的应用程序中可能会有更多的页面浏览量,并且其中大多数都需要 page_template。您的其他视图也可以使用我们定义的相同 page_template 服务。所以我们开始从容器中得到一些重用。
你基本上只是继续向容器添加服务。
您可以为此使用 Pimple,但制作您自己的容器也很有帮助。真的不多说了。
我有一长串依赖注入来显示包含文章、导航等的页面。目前我将它们放在一个名为 index.php 的文件中以将它们粘合在一起。
index.php,
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
use MyCustomVerndorName\Slug\Mapper\SlugMapper;
.... (more)
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Nav model.
$NavModel = new NavModel();
$NavMapper = new NavMapper($PdoAdapter);
$NavService->setMapper($NavMapper)->setModel($NavModel);
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
... (more)
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
... (more)
$NavChildrenComponent = new NavChildrenComponent($PdoAdapter);
... (more)
// Inject components.
$NavMapper->addComponent($NavChildrenComponent);
$NavMapper->addComponent($NavLanguageComponent);
// Controll the slug.
$SlugController->setService($SlugService)->fetchRow([
"url" => $url
]);
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
在我的 router.php 中(我正在使用 AltoRouter),
use AltoRouter as Router;
$Router = new Router();.
$Router->map('GET', '/', '/article/container');
... (and other routes)
if($match)
{
$target = $match['target'];
$url = isset($match['params']['url']) ? $match['params']['url'] : DEFAULT_HOMEPAGE;
$language = isset($match['params']['language']) ? $match['params']['language'] : null;
include __DIR__ . $target . '.php';
}
我正在考虑将 index.php 中的依赖项注入列表放入容器 class 以便我可以在需要时调用它 class,
例如 router.php、
$Router->map('GET', '/', 'MyCustomVerndorName\Article\Container\ArticleContainer');
....
new $target($PdoAdapter, $url, $language);
还有这个容器class,
namespace MyCustomVerndorName\Article\Container;
// Mapper.
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
...
class ArticleContainer
{
/*
* Construct dependency.
*/
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
// Slug.
$SlugService = new SlugService();
$SlugController = new SlugController();
// Nav.
$NavService = new NavService();
$NavController = new NavController();
// Article.
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
...
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
...
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
}
}
基本上,我把所有的依赖列表都放到了__construct
,
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
...
}
那么,这是做 DI 容器的正确方法,而不依赖 PHP 的众所周知的容器(例如 Pimple,Symfony\DependencyInjection, 等等)?
传统上,DI 容器returns 按需提供服务。您所说的 ArticleContainer 实际上只是一个函数,然后呈现一个视图。它做了很多 DI 注入,但它不是容器。
假设您有一个正确初始化的真实容器。您的代码如下所示:
$container = new Container();
// Some initialization
// Now use it
$viewArticle = $container->get('view_article');
echo $viewArticle->render('index.php');
希望您能看出其中的区别。初始化完成后,您的应用程序只需拉出它需要的视图并呈现它。无需担心 pdo 或 url 等
那么我们如何将我们的文章视图服务放入容器中呢?
$container = new Container();
// Some initialization
$container->set('page_template',function($container)
{
return new PageTemplate();
}
$container->set('article_view',function($container)
{
$articleView = new ArticleView(
$container->get('page_template',
$container->get('article_model')
);
$articleView->setSlug($container->get('slug_model');
$articleView->setNav ($container->get('nav_model');
return $articleView;
};
// Now use it
$viewArticle = $container->get('article_view');
echo $viewArticle->render('index.php');
所以我们为我们的容器定义了两个服务函数。当我们执行 $container->get('article_view'); 时,容器以容器本身作为参数调用该函数。该函数通过从容器中拉出依赖项然后 returns 新对象来创建所需的 class。
假设您的应用程序中可能会有更多的页面浏览量,并且其中大多数都需要 page_template。您的其他视图也可以使用我们定义的相同 page_template 服务。所以我们开始从容器中得到一些重用。
你基本上只是继续向容器添加服务。
您可以为此使用 Pimple,但制作您自己的容器也很有帮助。真的不多说了。