laravel框架底層解析
本文參考陳昊《Laravel框架關鍵技術解析》,搭建一個屬於自己的簡化版服務容器。
其中涉及到反射、自動載入,還是需要去了解一下。
laravel服務容器
-
建立專案空資料夾(如 mylaravel)
-
新增
composer.json
,執行composer install
{
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"type": "project",
"autoload": {
"classmap": [
],
"psr-4": {
"App\": "app/"
}
}
}
目的是為了學習、利用composer的自動載入。
-
檔案路徑如下所示
-
mylaravel
-
app
-
Traveller
-
Traveller.php
-
-
Visit
-
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 AppVisit;
interface Visit
{
public function go();
}
Leg.php
介面的一種實現
<?php
namespace AppVisit;
Class Leg implements Visit
{
public function go()
{
echo "walk to tibet!";
}
}
Traveller.php
相當於Controller下的方法
<?php
namespace AppTraveller;
use AppVisitVisit;
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(`AppVisitVisit`, `AppVisitLeg`);
$app->bind(`Traveller`, `AppTravellerTraveller`);
//通過容器實現依賴注入,完成類的例項化
$tra = $app->make("AppTravellerTraveller");
$tra->visitTibet();
}
}
$b = new Index;
$b->index();