Функция exec()
просто запускает команду в ОС, как вы используете оболочку или терминал.Это все еще «блокирующий» процесс.
В linux довольно легко сделать его без блокировки, просто добавив
php -f $file > /dev/null &
, который > /dev/null
отправляет выходные данные из STDOUT и STDERR в корзинуи &
фактически заставляет его работать без блокировки.
В Windows вы должны сделать это совершенно по-другому, но вы можете использовать COM('WScript.Shell')
следующим образом:
$WshShell = new \COM('WScript.Shell');
$cmd = "cmd /C php $file";
$oExec = $WshShell->Run($cmd, 0, false)
Для удобства я написал оболочку для них, которая будет определять, используете ли вы Windows илиLinux.Вы можете найти его на GitHub или на источнике:
class BgProcess{
/**
*
* @var string
*/
protected $_comand;
/**
*
* @var boolean
*/
protected $_osWin;
/**
*
* @param string $arg0, $arg1 ...
* $arg0 is location of php file to run
* $arg1 ..is additional params to send to script
*
* eg. new BgProcess( '/home/cli_scripts/script.php', 'true', 'false' );
*
*/
public function __construct($arg0){
if(stripos(php_uname('s'), 'win') > -1){
$this->_osWin = true;
}else{
$this->_osWin = false;
}
$args = func_get_args();
if(empty($args)){
throw new Exception(__CLASS__.' arguments required' );
}
$file = str_replace('\\', '/', array_shift($args));
$script = escapeshellarg($file).' '.implode(' ', array_map('escapeshellarg', $args));
if(false !== ($phpPath = $this->_getPHPExecutableFromPath())){
if($this->_osWin){
$WshShell = new \COM('WScript.Shell');
$cmd = 'cmd /C '.$phpPath.' '.$script;
$oExec = $WshShell->Run($cmd, 0, false);
}else{
$cmd = $phpPath.' -f '.$script.' > /dev/null &';
exec($cmd, $oExec);
}
$this->_comand = $cmd;
}else{
throw new Exception( 'Could not find php executable' );
}
}
/**
*
* @return string
*/
public function getCommand(){
return $this->_comand;
}
/**
*
* @return string|boolean
*/
protected function _getPHPExecutableFromPath() {
$paths = explode(PATH_SEPARATOR, getenv('PATH'));
if($this->_osWin){
foreach ($paths as $path) {
if (strstr($path, 'php')){
$php_executable = $path . DIRECTORY_SEPARATOR . 'php.exe';
if(file_exists($php_executable) && is_file($php_executable)){
return $php_executable;
}
}
}
}else{
foreach ($paths as $path) {
$php_executable = $path . DIRECTORY_SEPARATOR . "php";
if (file_exists($php_executable) && is_file($php_executable)) {
return $php_executable;
}
}
}
return false;
}
}
Вы используете его вот так
new BgProcess($file);
//php -f $file > /dev/null &
Если вы хотите поместить аргументы в
new BgProcess($file, $arg1);
//php -f $file $arg1 > /dev/null &
new BgProcess($file, $arg1, $arg2);
//php -f $file $arg1 $arg2 > /dev/null &
Как обычно, вы можете использовать $argv[0]
для получения файла, $argv[1]
для первого аргумента в скрипте, выполняемого этим.Есть несколько других предостережений при запуске PHP в командной строке, например, $_SERVER['HTTP_HOST']
не существует.Но я не буду освещать их все здесь, так как это так.Я просто упомяну это для полноты.
Эта часть _getPHPExecutableFromPath()
пытается найти путь php.exe
.Это очень помогает установить его в переменных среды в Windows.Я предлагаю просто прибегнуть к помощи «установить путь php в windows», потому что это зависит от вашей версии windows, и мне не хочется делать кучу скриншотов.
На самом деле я написал несколько более сложную версию этого длязапускать фоновые рабочие для RabbitMq, но он должен работать для всего, что нужно запускать без блокировки.
Наконец, если вам интересно, почему вам отказывают в голосовании по вашему вопросу, это потому, что это слишком широкая тема, иВы действительно не публиковали код.Переполнение стека связано с конкретной проблемой кодирования.
Единственная причина, по которой я вообще ответил, это то, что у меня есть такой класс, который я могу легко предоставить.Я также, вероятно, потрачу 3 дня, чтобы понять, как это сделать в Windows (так что я горжусь этим)
Надеюсь, это поможет!