本文參考陳昊《Laravel框架關鍵技術解析》,搭建一個屬於本身的簡化版服務容器。
其中涉及到反射、自動加載,仍是須要去了解一下。php
創建項目空文件夾(如 mylaravel)laravel
添加composer.json
,執行composer install
json
{ "name": "laravel/laravel", "description": "The Laravel Framework.", "keywords": ["framework", "laravel"], "license": "MIT", "type": "project", "autoload": { "classmap": [ ], "psr-4": { "App\\": "app/" } } }
目的是爲了學習、利用composer的自動加載。app
文件路徑以下所示composer
mylaravel框架
app函數
Traveller學習
Traveller.phpui
Visitthis
Leg.php
Visit.php
Container.php
Index.php
vendor
composer.json
簡化版Container.php
<?php namespace App; Class Container { protected $bindings = []; /** * 綁定接口和生成相應實例的回調函數 * @param $abstract 服務名稱 * @param null $concreate 回調函數或名稱 * @param bool $shared 是否爲單例 * */ public function bind($abstract, $concrete = null, $shared = false) { if ( ! $concrete instanceof \Closure) { // 若是提供的參數不是回調函數,則產生默認的回調函數 $concrete = $this->getClosure($abstract, $concrete); } $this->bindings[$abstract] = compact('concrete', 'shared'); } //默認的回調函數 protected function getClosure($abstract, $concrete) { //生成實例的回調函數, $c通常爲ioc容器對象 return function($c) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? 'build' : 'make'; return $c->$method($concrete); }; } //生成實例對象,首先解決接口和要實例化類之間的依賴 public function make($abstract) { $concrete = $this->getConcrete($abstract); if ($this->isBuildable($concrete, $abstract)) { $object = $this->build($concrete); } else { $object = $this->make($concrete); } return $object; } protected function isBuildable($concrete, $abstract) { return $concrete === $abstract || $concrete instanceof \Closure; } //獲取綁定的回調函數 protected function getConcrete($abstract) { if ( ! isset($this->bindings[$abstract])) { return $abstract; } return $this->bindings[$abstract]['concrete']; } //實例化對象 public function build($concrete) { if ($concrete instanceof \Closure) { return $concrete($this); } $reflector = new \ReflectionClass($concrete); if ( ! $reflector->isInstantiable()) { echo $message = "Target [$concrete] is not instantiable."; } $constructor = $reflector->getConstructor(); if (is_null($constructor)) { return new $concrete; } $dependencies = $constructor->getParameters(); $instances = $this->getDependencies($dependencies); return $reflector->newInstanceArgs($instances); } protected function getDependencies($parameters) { $dependencies = []; foreach ($parameters as $parameter) { $denpendency = $parameter->getClass(); if (is_null($denpendency)) { $dependencies[] = NULL; } else { $dependencies[] = $this->resolveClass($parameter); } } return (array) $dependencies; } protected function resolveClass(\ReflectionParameter $parameter) { return $this->make($parameter->getClass()->name); } }
Visit.php
接口
<?php namespace App\Visit; interface Visit { public function go(); }
Leg.php
接口的一種實現
<?php namespace App\Visit; Class Leg implements Visit { public function go() { echo "walk to tibet!"; } }
Traveller.php
至關於Controller下的方法
<?php namespace App\Traveller; use App\Visit\Visit; Class Traveller { protected $trafficTool; //Visit是抽象類,index中將leg注入到了容器,取代了Visit public function __construct(Visit $visit) { $this->trafficTool = $visit; } public function visitTibet() { $this->trafficTool->go(); } }
Index.php
<?php namespace App; //調用composer的自動加載 require '../vendor/autoload.php'; Class Index { public function index() { //實例化ioc容器 $app = new Container(); //容器填充 $app->bind('App\Visit\Visit', '\App\Visit\Leg'); $app->bind('Traveller', '\App\Traveller\Traveller'); //經過容器實現依賴注入,完成類的實例化 $tra = $app->make("\App\Traveller\Traveller"); $tra->visitTibet(); } } $b = new Index; $b->index();