EasySwoole 框架加入 HyperfCommand

李銘昕發表於2019-10-24

倉庫地址

試用 EasySwoole 自定義命令

建立檔案

<?php

declare(strict_types=1);

namespace App\Command;

use EasySwoole\EasySwoole\Command\CommandInterface;

class DemoCommand implements CommandInterface
{
    public function commandName(): string
    {
        return 'demo:command';
    }

    public function exec(array $args): ?string
    {
        var_dump('Hello World');

        return 'success';
    }

    public function help(array $args): ?string
    {
        return 'help';
    }
}

執行

$ php easyswoole
  ______                          _____                              _
 |  ____|                        / ____|                            | |
 | |__      __ _   ___   _   _  | (___   __      __   ___     ___   | |   ___
 |  __|    / _` | / __| | | | |  \___ \  \ \ /\ / /  / _ \   / _ \  | |  / _ \
 | |____  | (_| | \__ \ | |_| |  ____) |  \ V  V /  | (_) | | (_) | | | |  __/
 |______|  \__,_| |___/  \__, | |_____/    \_/\_/    \___/   \___/  |_|  \___|
                          __/ |
                         |___/
Welcome To EASYSWOOLE Command Console!
Usage: php easyswoole [command] [arg]
Get help : php easyswoole help [command]
Current Register Command:
demo:command
help
install
start
stop
reload
phpunit

$ php easyswoole demo:command
string(11) "Hello World"
success

不得不說,還是相當簡潔的。

改造

接下來,讓我們開始改造一部分程式碼,給 EasySwoole 插上 Hyperf 的 Command。

EasySwoole 執行模式十分簡單,所有的命令都儲存再 CommandContainer 中,所以我們大可以修改入口檔案,把其中的命令全部查出來,動態翻譯成 HyperfCommand,然後直接執行 HyperfCommand 就可以了。

為了不與 easyswoole 命令列衝突,我們新建一個 hyperf 好了。

首先我們建立一個元件

$ composer create hyperf/component-creater hyperf
Installing hyperf/component-creater (v1.1.1)
  - Installing hyperf/component-creater (v1.1.1): Downloading (100%)
Created project in hyperf
> Installer\Script::install
Setting up optional packages
What is your component name (hyperf/demo): hyperf-cloud/easyswoole-command
What is your component license (MIT) :
What is your component description : HyperfCommand for EasySwoole
What is your namespace (HyperfCloud\EasyswooleCommand):
Removing installer development dependencies

  Do you want to use hyperf/framework component ?
  [1] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n):

  Do you want to use hyperf/di component ?
  [1] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n):

...

並給元件增加 "hyperf/command": "1.1.*" 依賴。

下面修改根目錄 composer.json

{
    "require": {
        "easyswoole/easyswoole": "3.x",
        "hyperf-cloud/easyswoole-command": "dev-master"
    },
    "require-dev": {
        "swoft/swoole-ide-helper": "^4.2",
        "friendsofphp/php-cs-fixer": "^2.14",
        "mockery/mockery": "^1.0",
        "phpstan/phpstan": "^0.11.2"
    },
    "autoload": {
        "psr-4": {
            "App\\": "App/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "sort-packages": true
    },
    "scripts": {
        "test": "co-phpunit -c phpunit.xml --colors=always",
        "cs-fix": "php-cs-fixer fix $1",
        "analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./App"
    },
    "repositories": {
        "hyperf": {
            "type": "path",
            "url": "./hyperf"
        },
        "packagist": {
            "type": "composer",
            "url": "https://mirrors.aliyun.com/composer"
        }
    }
}

接管CommandInterface

讓我們建立一個 EasySwooleCommand 來接管所有的 CommandInterface

<?php

declare(strict_types=1);

namespace HyperfCloud\EasyswooleCommand;

use EasySwoole\EasySwoole\Command\CommandInterface;
use EasySwoole\EasySwoole\Core;
use Hyperf\Command\Command;
use Symfony\Component\Console\Input\InputOption;

class EasySwooleCommand extends Command
{
    /**
     * @var CommandInterface
     */
    protected $command;

    /**
     * @var bool
     */
    protected $coroutine = false;

    public function __construct(CommandInterface $command)
    {
        parent::__construct($command->commandName());
        $this->command = $command;
    }

    public function configure()
    {
        $this->addOption('args', 'a', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'EasySwoole 入參', []);
    }

    public function handle()
    {
        $args = $this->input->getOption('args');

        if (in_array('produce', $args)) {
            Core::getInstance()->setIsDev(false);
        }
        Core::getInstance()->initialize();

        $result = $this->command->exec($args);

        $this->output->success($result);
    }
}

增加 Application 初始化所有 CommandContainer 中的 Command

<?php

declare(strict_types=1);

namespace HyperfCloud\EasyswooleCommand;

use EasySwoole\Component\Singleton;
use EasySwoole\EasySwoole\Command\CommandContainer;
use Hyperf\Command\Command;
use Hyperf\Contract\ApplicationInterface;
use Symfony\Component\Console\Application as SymfonyApplication;

class Application implements ApplicationInterface
{
    use Singleton;

    protected $commands;

    public function __construct()
    {
        $container = CommandContainer::getInstance();

        $list = $container->getCommandList();

        foreach ($list as $name) {
            $this->commands[] = new EasySwooleCommand($container->get($name));
        }
    }

    public function add(Command $command)
    {
        $this->commands[] = $command;
    }

    public function run()
    {
        $application = new SymfonyApplication();
        foreach ($this->commands as $command) {
            $application->add($command);
        }

        return $application->run();
    }
}

最後改造入口函式

<?php

declare(strict_types=1);

use EasySwoole\EasySwoole\Command\CommandRunner;
use HyperfCloud\EasyswooleCommand\Application;

defined('IN_PHAR') or define('IN_PHAR', boolval(\Phar::running(false)));
defined('RUNNING_ROOT') or define('RUNNING_ROOT', realpath(getcwd()));
defined('EASYSWOOLE_ROOT') or define('EASYSWOOLE_ROOT', IN_PHAR ? \Phar::running() : realpath(getcwd()));

$file = EASYSWOOLE_ROOT . '/vendor/autoload.php';
if (file_exists($file)) {
    require $file;
} else {
    die("include composer autoload.php fail\n");
}

// 初始化 CommandContainer
CommandRunner::getInstance();

if (file_exists(EASYSWOOLE_ROOT . '/bootstrap.php')) {
    require_once EASYSWOOLE_ROOT . '/bootstrap.php';
}

Application::getInstance()->run();

執行命令 demo:command

$ php hyperf.php demo:command
string(11) "Hello World"

 [OK] success

啟動 Server

$ php hyperf.php start -a produce

建立 HyperfCommand

接下來,我們建立一個 HyperfCommand 看看效果。

<?php

declare(strict_types=1);

namespace App\Command;

use Hyperf\Command\Command;

class Demo2Command extends Command
{
    public function __construct()
    {
        parent::__construct('demo:command2');
    }

    public function handle()
    {
        var_dump('Hello Hyperf Command.');
    }
}

修改 bootstrap.php

<?php

declare(strict_types=1);

use EasySwoole\EasySwoole\Command\CommandContainer;
use App\Command\{DemoCommand, Demo2Command};
use HyperfCloud\EasyswooleCommand\Application;

CommandContainer::getInstance()->set(new DemoCommand());
Application::getInstance()->add(new Demo2Command());

執行結果

$ php hyperf.php demo:command2
string(21) "Hello Hyperf Command."

寫在最後

Hyperf 是基於 Swoole 4.4+ 實現的高效能、高靈活性的 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 協議》,轉載必須註明作者和本文連結
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

相關文章