單位的主項目是用ThinkPHP 3.1 開發的. 功能越來越跟不上發展 , 而老代碼迭代的難度又很大 . 重構已經提上了日程, 但拋下主營業務來重構是不實際的 . 所以目前的思路是 , 將原有功能拆分成一個個獨立的組件 , 脫離ThinkPHP 3.1 運行, 未來再移植到新架構裏.
用慣了Laravel的人 , 自然很快想到了引入Laravel的IoC容器 . 它有以下好處:
- 可以用來管理各種複雜的依賴關係
- 方便引入第三方依賴包
- 可以面向接口來規範重構
- 利於迭代,一組依賴中,舊的實例可以逐個改成新的實例,而不影響調用
- 可以用facade爲功能模塊提供簡潔的Api接口
- 未來可直接引入laravel的 隊列, 事件, EloquentORM 等核心機制
那麼在ThinkPHP引入IoC , 需要幾步呢?如下:
- 確保ThinkPHP 3.1 項目運行在 php 5.4 以上環境中
- 給ThinkPHP 3.1 引入Composer
- 獨立出Laravel的Container組件
- 爲擴展功能設計架構
- 創建引入ThinkPHP的引導文件
一. 給ThinkPHP 3.1 引入Composer
時至今日 , ThinkPHP自身的autoload管理功能已經非常老舊了 , 有這幾個關鍵的痛點:
- 沒有命名空間,大量關鍵類同名
- 引入外部庫還要用令人費解的import()方法
- 生成autoload的代碼位置 , 在設計理念上有錯
靠ThinkPHP去管理各種現代依賴 , 基本是不可能完成的任務 . 這時Composer就大顯身手了.
我們可以在任意文件夾創建 Composer.json
文件 , 然後按自己的設想任意構建擴展.
運行composer install
指令後,composer就自動爲我們下載了所有依賴,並生成了 vendor/autoload.php
文件.
瞥一眼vendor/autoload.php
文件,會發現它其實就幹了兩件事 :
- 引入了
vendor/composer/ClassLoader.php
,這裏註冊了各種 Autoload 機制的引用文件方法 - 引入了按
composer.json
文件定義的classmap,files,psr-0,psr-4等規範 , 生成的類名路徑映射關係文件.
所以我們只要把 vendor/autoload.php
在ThinkPHP項目中require
進來, 就可以隨心所欲使用任何自定義類和擴展,再不要受TP3.1規範的約束了.
問題是autoload.php
要在哪裏引入比較合適呢? 經過反覆測試,還是在Public/index.php
中引入較好:
/**
* 系統調試設置
* 項目正式部署後請設置爲false
*/
define ( 'APP_DEBUG', true );
define ( 'APP_PATH', realpath(dirname(__FILE__) ."/../") ."/" );
define ( 'WEB_PATH', realpath(dirname(__FILE__)) ."/" );
/**
* 引入核心入口
* ThinkPHP亦可移動到WEB以外的目錄
*/
//------------!!!在這裏引入Composer的autoload!!------------//
require '../../Extends/vendor/autoload.php';
require '../ThinkPHP/ThinkPHP.php';
這是因爲ThinkPHP有非常糟糕的引導機制:
index.php --require--> ThinkPHP.php --require--> Common/runtime.php
這個過程是單線的,穿插大量必要的宏定義,和大量的if邏輯.
最關鍵的啓動代碼 Think::Start();
卻在 runtime.php
最後一行執行.
這好比把衣服褲子鞋子做成了一件連體服.想要加一根腰帶,要麼脫光,要麼剪開衣服.與其在劈頭蓋臉的if else中找剪裁點,還是選擇脫光吧.
下一節聊聊如何把Laravel的Container組件獨立出來