有些時候在某一個項(xiàng)目中, 使用了一個第三方包, 但是會發(fā)現(xiàn)某一些地方不符合項(xiàng)目需求. 或者需要在包代碼里注入一段自己的邏輯. 我們可以選擇自己維護(hù)一個分支, 或者干脆改vendor文件夾, 并它他加入代碼管理. 但對于要修改少量代碼時, 這樣做貌似不太'優(yōu)雅'
請先查閱函數(shù)spl_autoload_register文檔
其實(shí)composer也是利用這個函數(shù)來實(shí)現(xiàn)自動加載的.
php代碼執(zhí)行時, 如果遇到代碼里依賴了一個類, 而這個類在當(dāng)前進(jìn)程中不存在時, php 會按照加載器隊(duì)列順序調(diào)用通過spl_autoload_register函數(shù)注冊過的類加載器. 直到某個加載器執(zhí)行完后, 這個被依賴的類被加載進(jìn)當(dāng)前進(jìn)程空間, 或者所有加載器都執(zhí)行完這個類仍不存在, 并拋出類不存在的異常.
所以我們也可以利用spl_autoload_register函數(shù), 注冊一個加載器, 并使其在隊(duì)列里位于composer加載器之前. 當(dāng)php需要加載我們要改動的第三方代碼包里的類時, 我們加載自己改好的php文件, 而不是vendor包里的php文件. 這樣就達(dá)到了覆蓋的目的.
煮個栗子:
我寫了一個自動搶餓了么最大外賣紅包swoole程序. 大概流程就是, 利用hanson/vbot 包監(jiān)聽微信群里發(fā)送的紅包鏈接, 并把鏈接推送到紅包隊(duì)列, 然后有個進(jìn)程使用小號輪訓(xùn)餓了么接口, 等紅包的下一個就是最大時, 用大號去領(lǐng), 就領(lǐng)到了, 但是有個問題:
vbot 包有個message handler類, 里面有個listen方法. 這個方法里會調(diào)用微信網(wǎng)頁版的接口. 當(dāng)收到微信消息時會調(diào)用用戶的消息處理器, 并且此方法是while(true)循環(huán).所以一旦執(zhí)行l(wèi)isten方法, 整個進(jìn)程是會阻塞在這個方法里的, 就算用swoole的異步定時器也無力回天. 但是我又有個需求, 就是異步發(fā)送消息: 當(dāng)某個紅包的最大紅包來臨時, 可以配置不自動搶, 而是把鏈接轉(zhuǎn)發(fā)到一個'內(nèi)部群', 由群員搶最大紅包. 所以我只好修改一下這個類了, 把while(true)循環(huán)改成swoole的定時器

項(xiàng)目目錄結(jié)構(gòu)

注意到, overwrite文件夾, 就是我用來放覆蓋第三方代碼php文件的目錄
里面的autoload.php文件內(nèi)容:
<?php
spl_autoload_register(function ($cls) {
$map = [
'Hanson\Vbot\Core\MessageHandler' => __DIR__ . '/MessageHandler.php',
'Hanson\Vbot\Core\Server' => __DIR__ . '/Server.php',
];
if (isset($map[$cls])) {
echo $cls . ' loaded' . PHP_EOL;
include $map[$cls];
return true;
}
// 注意需要設(shè)置prepend參數(shù)為true
}, true, true);
項(xiàng)目的composer.json加載了這autoload.php:
{
"require": {
"hanson/vbot": "^2.0",
"symfony/debug": "^4.1"
},
"autoload": {
"psr-4": {
"App\\": "src/"
},
"files": ["src/overwrite/autoload.php"]
}
}
請自行體會