分享一个可以使用代码方式调用自定义命令的方法,类似Artisan::call

Ace华

最终效果

可以像laravel那样使用 Artisan::call('自定义命令');来在代码中使用自定义命令,不了解什么是自定义命令的,可以查看:https://www.workerman.net/doc/webman/plugin/console.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%91%BD%E4%BB%A4

使用自定义命令必须先安装webman/console:

composer require webman/console

效果如下,可以使用代码调用 config:mysql

// 每隔10秒执行一次
\Workerman\Timer::add(10, function () {
    CommandUtil::call("config:mysql");
});

源码

复制到php文件中,这里取名为 CommandUtil

<?php
namespace app\common;

use Symfony\Component\Console\Command\LazyCommand;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Throwable;
use Webman\Console\Command;
use Webman\Console\Util;

class CommandUtil extends Command
{
    public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
    {
        parent::__construct($name, $version);
        if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
            $this->installCommands($command_path);
        }
    }

    /**
     * 执行命令
     * @param string $commandStr
     * @return int
     * @throws Throwable
     */
    public function handle(string $commandStr): int
    {
        $command = $this->find($commandStr);
        if ($command instanceof LazyCommand) {
            $command = $command->getCommand();
        }
        $input  = new ArgvInput();
        $output = new ConsoleOutput();
        return $this->doRunCommand($command, $input, $output);
    }

    /**
     * 调用命令的静态方法
     * @param string $commandStr
     * @return void
     * @throws Throwable
     */
    public static function call(string $commandStr)
    {
        $command = new self();
        $command->handle($commandStr);
    }
}

已知问题

此方法只能实现在后端调用,也就是不能完全像laravel那样,可以通过访问浏览器的某个控制器中的方法来调用,会报错,报错如下:

ErrorException: fwrite(): Write of 127 bytes failed with errno=22 Invalid argument in D:\4.PHP\Code\webman-v1\vendor\symfony\var-dumper\Dumper\AbstractDumper.php:178
349 2 0
2个评论

shiroi

我这里调用是没问题的,下面是代码

  • app/command/Test.php

    namespace app\command;
    
    use Symfony\Component\Console\Command\LazyCommand;
    use Symfony\Component\Console\Input\ArgvInput;
    use Symfony\Component\Console\Output\ConsoleOutput;
    use Throwable;
    use Webman\Console\Command;
    use Webman\Console\Util;
    
    class Test extends Command
    {
        public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
        {
            parent::__construct($name, $version);
            if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
                $this->installCommands($command_path);
            }
        }
    
        /**
         * 执行命令
         * @param string $commandStr
         * @return int
         * @throws Throwable
         */
        public function handle(string $commandStr): int
        {
            $command = $this->find($commandStr);
            if ($command instanceof LazyCommand) {
                $command = $command->getCommand();
            }
            $input  = new ArgvInput();
            $output = new ConsoleOutput();
            return $this->doRunCommand($command, $input, $output);
        }
    
        /**
         * 调用命令的静态方法
         * @param string $commandStr
         * @return void
         * @throws Throwable
         */
        public static function call(string $commandStr)
        {
            $command = new self();
            $command->handle($commandStr);
        }
    }
    • app/command/TestCommand.php
    namespace app\command;
    
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Input\InputOption;
    use Symfony\Component\Console\Input\InputArgument;
    use Symfony\Component\Console\Output\OutputInterface;
    
    class TestCommand extends Command
    {
        protected static $defaultName = 'test:command';
        protected static $defaultDescription = 'test command';
    
        /**
         * @return void
         */
        protected function configure()
        {
            $this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
        }
    
        /**
         * @param InputInterface $input
         * @param OutputInterface $output
         * @return int
         */
        protected function execute(InputInterface $input, OutputInterface $output): int
        {
            $name = $input->getArgument('name');
            $output->writeln('Hello test:command');
            return self::SUCCESS;
        }
    
    }
    • app/controller/TestController.php
    namespace app\controller;
     class TestController
    {
        public function test()
        {
            dump("控制层调用:" . $request->url());
            Test::call('test:command');
        }
    }

    截图

  • Ace华 23天前

    没看出你的和我的有什么区别,应该是不用使用dump方法吧,你这个测试里面没有使用到dump方法的

  • shiroi 21天前

    echo和dump都一样的,都是输出打印文本,只是让你知道我触发了api接口

shiroi

有报错我就重写了啊,我给你发我的composer.json得了

     "php": ">=7.4",
     "workerman/webman-framework": "^1.5.0",
     "monolog/monolog": "^2.0",
     "webman/console": "^1.3",
     "webman/admin": "^0.6.33",
     "webman/event": "^1.0",
     "mathieuviossat/arraytotexttable": "^1.0",
     "webman/think-cache": "^1.0",
     "symfony/cache": "^5.4",
     "robmorgan/phinx": "^0.14.0",
     "next/var-dumper": "^0.1.0",
     "psr/container": "1.1.1",
     "php-di/php-di": "6",
     "doctrine/annotations": "1.14",
     "ratchet/pawl": "^0.4.1",
     "workerman/crontab": "^1.0",
     "amphp/amp": "^2.6",
     "amphp/sync": "^1.4",
     "phpseclib/phpseclib": "^3.0",
     "topthink/think-template": "^2.0",
     "topthink/think-validate": "^2.0",
     "symfony/process": "^5.4",
     "shopwwi/webman-filesystem": "^1.1",
     "phpoffice/phpspreadsheet": "^1.12",
     "saithink/laravelorm-log": "^1.0",
     "overtrue/wechat": "~5.0",
     "webman/redis-queue": "^1.3",
     "illuminate/redis": "^8.0",
     "webman-tech/symfony-lock": "^2.0"
  • 暂无评论

Ace华

760
积分
0
获赞数
0
粉丝数
2023-02-14 加入
×
🔝