// 聲明一個應用主體對象並加載配置文件
$container = new \Slim\Container
$app = new \Slim\App($container);
/**
* Example GET route
*
* @param \Psr\Http\Message\ServerRequestInterface $req PSR7 request
* @param \Psr\Http\Message\ResponseInterface $res PSR7 response
* @param array $args Route parameters
*
* @return \Psr\Http\Message\ResponseInterface
*/
$app->get('/foo', function ($req, $res, $args) {
$myService = $this->get('myService');
return $res;
});
你可以這樣隱式地從容器中取得服務:
/**
* Example GET route
*
* @param \Psr\Http\Message\ServerRequestInterface $req PSR7 request
* @param \Psr\Http\Message\ResponseInterface $res PSR7 response
* @param array $args Route parameters
*
* @return \Psr\Http\Message\ResponseInterface
*/
$app->get('/foo', function ($req, $res, $args) {
$myService = $this->myService;
return $res;
});
/**
* 創建一個應用主體(PS:應用主體是博主從Yii2框架應用主體概念得到,應用主體可理解爲貫穿應用程序執行生命週期最重要的那個類)
* Create new application
*
* @param ContainerInterface|array $container Either a ContainerInterface or an associative array of app settings
* @throws InvalidArgumentException when no container is provided that implements ContainerInterface
*/
public function __construct($container = [])
{
// 傳入$container是一個數組,說明傳入了一些配置且使用了Slim默認的Pimple依賴注入容器
if (is_array($container)) {
$container = new Container($container);
}
// 容器不是實現自ContainerInterface接口,拋出異常
if (!$container instanceof ContainerInterface) {
throw new InvalidArgumentException('Expected a ContainerInterface');
}
// 依賴注入容器實例賦值爲應用主體$app的container屬性
$this->container = $container;
}
PSR-11 容器接口
/**
* Slim默認的依賴注入容器是Pimple
* Slim's default DI container is Pimple.
* Slim\App要求容器必須實現Psr\Container\Containerface接口
* 且若你使用第三方容器,如下這些服務也必須實現
* Slim\App expects a container that implements Psr\Container\ContainerInterface
* with these service keys configured and ready for use:
*
* - settings: an array or instance of \ArrayAccess
* - environment: an instance of \Slim\Interfaces\Http\EnvironmentInterface
* - request: an instance of \Psr\Http\Message\ServerRequestInterface
* - response: an instance of \Psr\Http\Message\ResponseInterface
* - router: an instance of \Slim\Interfaces\RouterInterface
* - foundHandler: an instance of \Slim\Interfaces\InvocationStrategyInterface
* - errorHandler: a callable with the signature: function($request, $response, $exception)
* - notFoundHandler: a callable with the signature: function($request, $response)
* - notAllowedHandler: a callable with the signature: function($request, $response, $allowedHttpMethods)
* - callableResolver: an instance of \Slim\Interfaces\CallableResolverInterface
*
* @property-read array settings
* @property-read \Slim\Interfaces\Http\EnvironmentInterface environment
* @property-read \Psr\Http\Message\ServerRequestInterface request
* @property-read \Psr\Http\Message\ResponseInterface response
* @property-read \Slim\Interfaces\RouterInterface router
* @property-read \Slim\Interfaces\InvocationStrategyInterface foundHandler
* @property-read callable errorHandler
* @property-read callable notFoundHandler
* @property-read callable notAllowedHandler
* @property-read \Slim\Interfaces\CallableResolverInterface callableResolver
*/
class Container extends PimpleContainer implements ContainerInterface
暫時可知,Container類繼承Pimple容器,且實現了ContainerInterface,由
Container類是Pimple依賴注入容器的核心類,我們會詳細講解。首先,我們從構造方法__construct()說起。
/**
* 創建新容器
* Create new container
*
* @param array $values The parameters or objects.
*/
public function __construct(array $values = [])
{
// 繼承父類的構造方法
parent::__construct($values);
// 獲取配置文件中settings配置項的值
$userSettings = isset($values['settings']) ? $values['settings'] : [];
// 註冊Slim需要的一些默認服務
$this->registerDefaultServices($userSettings);
}
我們瞭解下Container父類PimpleContainer的構造方法。 /**
* 實例化容器
* Instantiates the container.
*
* Objects and parameters can be passed as argument to the constructor.
*
* @param array $values The parameters or objects
*/
public function __construct(array $values = array())
{
// 實例化factories,protected屬性,且賦值爲\SplObjectStorage()實例化對象
// SplObjectStorage提供了從對象到數據的映射,或者忽略數據提供對象集
$this->factories = new \SplObjectStorage();
$this->protected = new \SplObjectStorage();
// 將傳入的配置項整合到容器對象
foreach ($values as $key => $value) {
$this->offsetSet($key, $value);
}
}
瞭解下offsetSet函數 /**
* 設置參數或閉包對象
* Sets a parameter or an object.
*
* Objects must be defined as Closures.
*
* Allowing any PHP callable leads to difficult to debug problems
* as function names (strings) are callable (creating a function with
* the same name as an existing parameter would break your container).
*
* @param string $id The unique identifier for the parameter or object
* @param mixed $value The value of the parameter or a closure to define an object
*
* @throws FrozenServiceException Prevent override of a frozen service
*/
public function offsetSet($id, $value)
{
if (isset($this->frozen[$id])) {
throw new FrozenServiceException($id);
}
// 將賦值給values數組,並用keys數組記錄
$this->values[$id] = $value;
$this->keys[$id] = true;
}
今天是柚子第一天健身,略有疲乏,且天色已晚,就到此爲止吧。明天會繼續我們的DI容器探險之旅~~