眾所周知 Hyperf 是不支援單獨啟動某個服務的,所以有類似需求的小夥伴確實比較頭疼。
作為 Hyperf 作者,接到過很多這類需求和 PR,但都被我斃了,因為框架提供了極大的自由度,這些東西完全可以自己擴充套件。
以下我們提供一種極為友好的方式,處理這個問題。
如何擴充套件
先讓我們閱讀一下 Symfony\Component\Console\Application
中的一段程式碼
$event = new ConsoleCommandEvent($command, $input, $output);
$e = null;
try {
$this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);
if ($event->commandShouldRun()) {
$exitCode = $command->run($input, $output);
} else {
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
}
} catch (\Throwable $e) {
$event = new ConsoleErrorEvent($input, $output, $e, $command);
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
$e = $event->getError();
if (0 === $exitCode = $event->getExitCode()) {
$e = null;
}
}
可以看到,我們在執行具體的 Command
前,會先觸發 ConsoleCommandEvent
事件,那麼我們只需要寫一個 Listener
,來觸發這個事件即可。
編寫 Listener
我們從 $event
中拿到對應的 Command
,然後新增我們的需要自定義的選項,然後過載以下 InputInterface
。
接下來我們只需要根據對應的 Option
修改 Config
中的配置即可。
程式碼如下
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Listener;
use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Input\InputOption;
/**
* @Listener
*/
class ConsoleCommandEventListener implements ListenerInterface
{
/**
* @var ContainerInterface
*/
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function listen(): array
{
return [
ConsoleCommandEvent::class,
];
}
/**
* @param ConsoleCommandEvent $event
*/
public function process(object $event)
{
if ($event instanceof ConsoleCommandEvent) {
$command = $event->getCommand();
$command->addOption('server', 'S', InputOption::VALUE_OPTIONAL, '需要啟動的服務');
$input = $event->getInput();
$input->bind($command->getDefinition());
if ($input->getOption('server') != null) {
$config = $this->container->get(ConfigInterface::class);
$servers = $config->get('server.servers', []);
$result = [];
foreach ($servers as $server) {
if ($input->getOption('server') == $server['name']) {
$result[] = $server;
}
}
if (empty($result)) {
throw new BusinessException(ErrorCode::SERVER_ERROR, '服務名不存在');
}
$config->set('server.servers', $result);
}
}
}
}
測試結果如下,可見符合我們的預期
$ php bin/hyperf.php start
[INFO] HTTP Server listening at 0.0.0.0:9502
[INFO] HTTP Server listening at 0.0.0.0:9501
^C
$ php bin/hyperf.php start -S http
[INFO] HTTP Server listening at 0.0.0.0:9501
^C
$ php bin/hyperf.php start -S http2
[INFO] HTTP Server listening at 0.0.0.0:9502
^C
寫在最後
Hyperf 是基於 Swoole 4.5+ 實現的高效能、高靈活性的 PHP 協程框架,內建協程伺服器及大量常用的元件,效能較傳統基於 PHP-FPM 的框架有質的提升,提供超高效能的同時,也保持著極其靈活的可擴充套件性,標準元件均基於 PSR 標準 實現,基於強大的依賴注入設計,保證了絕大部分元件或類都是 可替換 與 可複用 的。
框架元件庫除了常見的協程版的 MySQL 客戶端、Redis 客戶端,還為您準備了協程版的 Eloquent ORM、WebSocket 服務端及客戶端、JSON RPC 服務端及客戶端、GRPC 服務端及客戶端、Zipkin/Jaeger (OpenTracing) 客戶端、Guzzle HTTP 客戶端、Elasticsearch 客戶端、Consul 客戶端、ETCD 客戶端、AMQP 元件、Apollo 配置中心、阿里雲 ACM 應用配置管理、ETCD 配置中心、基於令牌桶演算法的限流器、通用連線池、熔斷器、Swagger 文件生成、Swoole Tracker、Blade 和 Smarty 檢視引擎、Snowflake 全域性ID生成器 等元件,省去了自己實現對應協程版本的麻煩。
Hyperf 還提供了 基於 PSR-11 的依賴注入容器、註解、AOP 面向切面程式設計、基於 PSR-15 的中介軟體、自定義程式、基於 PSR-14 的事件管理器、Redis/RabbitMQ 訊息佇列、自動模型快取、基於 PSR-16 的快取、Crontab 秒級定時任務、Translation 國際化、Validation 驗證器 等非常便捷的功能,滿足豐富的技術場景和業務場景,開箱即用。
本作品採用《CC 協議》,轉載必須註明作者和本文連結