zoukankan      html  css  js  c++  java
  • [Symfony2] 在命令或控制器里跑另一个命令的N种方法

    或许最容易想到的,是通过system或者exec里执行命令,只不过这么做显得太过粗线条对吧——系统调用函数系列不一定主机提供商允许运行,而且运行命令得重新初始化Symfony2框架运行环境,多浪费计算资源。

    这两个问题,最需要解决的是第一个问题。为了安全性,很多环境PHP的系统调用系列函数都被disable掉了。不过这个问题也应该好解决,我们来看看app/console文件到底执行了什么就明白了。

    原来就是新建了一个Application对象并注入了$kernel就行了啊……且慢,输入的参数是怎么传入命令的呢?我们再看看SymfonyComponentConsoleInputArgvInput类,看能不能发现什么:

    原来如此,ArgvInput在构建时,如果没有输入第一个参数,那么会自动采用$_SERVER['argv'](其实也就是$argv变量)作为传入的参数。

    当我们在命令行调用一个PHP脚本的时候,$argv是如下的样子:

    所以才会有array_shift($argv)一句,把app/console$argv里除掉,后面的处理并不需要它。

    那么,我们是不是可以通过创建一个Application的方式来运行Symfony2项目里的命令了呢?当然可以!你只用构件好一个ArgvInput作为Application的第一个参数就可以了,比如调用cache:clear命令:

    不过,在已有的命令或者控制器里,不必创建$kernel,因为$kernel已经有了,通过依赖注入容器你就可以获取:

    所以,之前$kernel = new AppKernel($env, $debug)那一行可以直接用上面的替换了,并且因为Kernel里已经包含了运行环境和debug开关等信息,你不用担心运行环境不一致的问题。

    以上的代码可以运行,但需要传一个毫无意义的app/console,确实有点不舒服。我们再继续深入代码,看看能不能不用ArgvInput作为输入参数,毕竟Symfony Console Component里又不止它一个Input。

    我们来看看Symfony/Component/Console/Input目录下实现InputInterface接口的类有啥。除了抽象类Input以外,还有它们:

    StringInput

    看名字就能大概猜出来使用方法。此类的构造函数的第一个参数为字符串,接下来我想不用我多说了吧。需要注意的是,命令里并不需要提到app/console

    看起来很符合我们的需求哦。

    ArrayInput

    好吧,这个是数组版本的StringInput。没啥好说的,注意数组里除了第一个元素以外,其他的全是key => value形式:

    接下来的改进

    话说,为什么运行命令必须得初始化一个Application啊?

    让我们来看看Application到底做了些啥:

    由此可见,从Application创建到执行run方法,做了下面这些事情:构造时注入了kernel并从kernel里获取了环境信息作为参数,并增了4个Symfony2命令必有的命令选项;运行时尝试启动kernel并做了一些初始化依赖的工作。且慢,代码里执行的是run命令,让我们来看看父类里run方法以及doRun方法做了什么:

    嗯,结果是一大段错误处理,以及抛出两个事件。真正执行的,还是$command->run($input, $output)这一句。如果大家还是想自己控制意外处理,并且不需要执行事件,其实是完全可以直接创建某个命令的实例并运行他的run方法。

    改进之后的代码:

    以执行doctrine:database:drop --force为例:

    目前为止,应该是性能最优的用代码调用Symfony2项目命令的方式了。

    提示:是否使用最后一种方式来调用命令,也得分情况:如果你调用命令是为了批处理(按顺序执行n个命令),使用Application来运行命令更 适合,毕竟可能会有处理命令运行和终止事件的监听器。如果你只需要某个命令的功能,比如清空数据库,那么你最好使用最后一种方式来调用命令帮你完成任务。 不过需要注意的是,有的命令是依赖Application的,这种情况则需要使用$command->setApplication($application)或者使用Application来运行命令,再或者,将命令注册为服务:

    当然,最好最好的方式:去看看你想调用的命令都执行了什么代码,把它们都找出来!

    最后再给个友情提示:如果不想在console下输出信息,可以改用NullOutput

  • 相关阅读:
    Vue 子组件接收父组件的值
    Vue 子组件调用父组件的方法
    dedecms大量删除文章后,列表页显示错误修复办法
    怎么才能快速的删除指定栏目、指定日期、指定id之间的织梦文章内容?
    怎么才能快速的彻底删除织梦文章内容?
    织梦删除专题,删除文章时出现错误inc_batchup.php on line 17 如何解决?
    windows环境下更改Mysql数据库存储位置的具体步骤
    JsonP原理
    建一个别人打不开的文件夹
    Dos环境变量修改
  • 原文地址:https://www.cnblogs.com/Jerry-blog/p/4919099.html
Copyright © 2011-2022 走看看