一個非常簡單且實用的IoC框架,相對於其他的Ioc框架有如下特點:
- 高效: 框架使用了非常實用且高效的算法,使得框架本身對應用的影響微乎其微,且框架提供了C擴展,最大限度的將性能提升到最高。
- 配置簡單: 大多數情況下幾乎不需要額外的配置
- 自動裝配: 基於PHPDocument的property屬性來自動裝配
- 懶加載: 所有被注入的變量的實例都為即用即取, 不會產生內存垃圾
- IDE友好: 因為利用的是PHP的標准規范, 兼容大部分IDE
安裝
編譯安裝,可以得到最大的效率:
$ git clone https://github.com/dustinfog/canoe-di.git $ cd canoe-di/ext $ phpize $ ./configure $ make $ sudo make install
而后編輯php.ini
[canoe-di] extension=canoe_di.so
composer安裝 (生產環境如果已經編譯安裝了擴展,此步驟可省略。在開發環境,PHP源碼可以讓IDE提供代碼完成提示,所以仍然推薦執行這一步):
composer require dustinfog/canoe-di
使用
獲取實例
class ClassA { } //DI容器在處理類型時,會在第一次遇到的時候實例化,並且在以后使用中以單例的方式使用。 $a = \Canoe\DI\Context::get(ClassA::class);
基於標注的裝配
class ClassC { } use \Canoe\DI\DITrait; use \Canoe\DI\Context; /** * @property ClassC $c */ class ClassA { //需要引入一個trait,用以處理$c的獲取 use DITrait; public function test() { //這里可以直接使用 print_r($this->c); } } $a = Context::get(ClassA::class); $a->test(); //試一下會發生什么
@uses標注:
uses可以指定屬性使用的類或者容器里的實例
interface InterfaceC { public function sayHello(); } class ClassWorld implements InterfaceC { public function sayHello() { echo "hello, world!\n"; } } class ClassC implements InterfaceC { private $name; public function __construct($name) { $this->name = $name; } public function sayHello() { echo "hello, $name!\n"; } } use \Canoe\DI\DITrait; use \Canoe\DI\Context; /** * @property InterfaceC $c1 {@uses ClassWorld} //使用類名 * @property InterfaceC $c2 {@uses c2} //使用容器內的ID */ class ClassA { //需要引入一個trait,用以處理$c的獲取 use DITrait; public function test() { print_r($this->c1); print_r($this->c2); } } Context::set("c2", new ClassC("Bob")); // 更好的選擇:Context::registerDefinition("c2", function(){new ClassC("Bob")}) $a = Context::get(ClassA::class); $a->test(); //試一下會發生什么
Singleton
有時候,我們需要在一個非DI環境里有限的使用DI,這時候每個系統與DI容器的先借點都在調用Context::get()顯得很丑陋,框架里提供了一個更加親民的調用方式:
use \Canoe\DI\SingletonTrait; class ClassA { use SingletonTrait; } $a = ClassA::getInstance(); // 與Context::get(ClassA::class)等價,但隱藏了Context調用。 $a = ClassA::getInstance("a1"); // 與Context::get("a1")等價,但做了進一步的類型檢查,即a1取到的實例與ClassA必須有"is a"的關系。
預先定義
上面的例子都是在運行時來實現自動裝配的,但在某些時候可能需要手動預先創建一些定 義,以備后續使,框架提供了簡單的支持.
//注冊類 Canoe\DI\Context::registerDefinition('a', ClassA::class); //注冊回調 Canoe\DI\Context::registerDefinition( 'b', function() { return new ClassB(); } ); //注冊實例 Canoe\DI\Context::set('c', new ClassC());
配置
大多數時候,預先定義都是寫在配置文件里,可以用下列的方法加載配置:
\Canoe\DI\Context::loadConfig( [ 'definitions' => [ //這里是定義 ClassB::class, ], 'beans' => [ //這里可以預定義一些實際的值 'uid' => 5, ], ]);
項目地址:https://github.com/dustinfog/canoe-di