diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69d4cbd7..31b9ee6a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,26 @@
CHANGELOG
=========
+5.2.0
+-----
+
+ * added `Process::setOptions()` to set `Process` specific options
+ * added option `create_new_console` to allow a subprocess to continue
+ to run after the main script exited, both on Linux and on Windows
+
+5.1.0
+-----
+
+ * added `Process::getStartTime()` to retrieve the start time of the process as float
+
+5.0.0
+-----
+
+ * removed `Process::inheritEnvironmentVariables()`
+ * removed `PhpProcess::setPhpBinary()`
+ * `Process` must be instantiated with a command array, use `Process::fromShellCommandline()` when the command should be parsed by the shell
+ * removed `Process::setCommandLine()`
+
4.4.0
-----
diff --git a/ExecutableFinder.php b/ExecutableFinder.php
index e2dd064d..eb8f0629 100644
--- a/ExecutableFinder.php
+++ b/ExecutableFinder.php
@@ -31,10 +31,8 @@ public function setSuffixes(array $suffixes)
/**
* Adds new possible suffix to check for executable.
- *
- * @param string $suffix
*/
- public function addSuffix($suffix)
+ public function addSuffix(string $suffix)
{
$this->suffixes[] = $suffix;
}
@@ -46,9 +44,9 @@ public function addSuffix($suffix)
* @param string|null $default The default to return if no executable is found
* @param array $extraDirs Additional dirs to check into
*
- * @return string|null The executable path or default value
+ * @return string|null
*/
- public function find($name, $default = null, array $extraDirs = [])
+ public function find(string $name, string $default = null, array $extraDirs = [])
{
if (\ini_get('open_basedir')) {
$searchPath = array_merge(explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs);
diff --git a/InputStream.php b/InputStream.php
index 4f8f7133..240665f3 100644
--- a/InputStream.php
+++ b/InputStream.php
@@ -17,6 +17,8 @@
* Provides a way to continuously write to the input of a Process until the InputStream is closed.
*
* @author Nicolas Grekas
+ *
+ * @implements \IteratorAggregate
*/
class InputStream implements \IteratorAggregate
{
@@ -67,7 +69,7 @@ public function isClosed()
}
/**
- * @return \Traversable
+ * @return \Traversable
*/
#[\ReturnTypeWillChange]
public function getIterator()
diff --git a/LICENSE b/LICENSE
index 88bf75bb..0138f8f0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2022 Fabien Potencier
+Copyright (c) 2004-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/PhpExecutableFinder.php b/PhpExecutableFinder.php
index 92e0262a..998808b6 100644
--- a/PhpExecutableFinder.php
+++ b/PhpExecutableFinder.php
@@ -29,11 +29,9 @@ public function __construct()
/**
* Finds The PHP executable.
*
- * @param bool $includeArgs Whether or not include command arguments
- *
- * @return string|false The PHP executable path or false if it cannot be found
+ * @return string|false
*/
- public function find($includeArgs = true)
+ public function find(bool $includeArgs = true)
{
if ($php = getenv('PHP_BINARY')) {
if (!is_executable($php)) {
@@ -91,7 +89,7 @@ public function find($includeArgs = true)
/**
* Finds the PHP executable arguments.
*
- * @return array The PHP executable arguments
+ * @return array
*/
public function findArguments()
{
diff --git a/PhpProcess.php b/PhpProcess.php
index dc064e0b..2bc338e5 100644
--- a/PhpProcess.php
+++ b/PhpProcess.php
@@ -58,18 +58,6 @@ public static function fromShellCommandline(string $command, string $cwd = null,
throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
}
- /**
- * Sets the path to the PHP binary to use.
- *
- * @deprecated since Symfony 4.2, use the $php argument of the constructor instead.
- */
- public function setPhpBinary($php)
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the $php argument of the constructor instead.', __METHOD__), \E_USER_DEPRECATED);
-
- $this->setCommandLine($php);
- }
-
/**
* {@inheritdoc}
*/
diff --git a/Pipes/AbstractPipes.php b/Pipes/AbstractPipes.php
index 9532e3ef..656dc032 100644
--- a/Pipes/AbstractPipes.php
+++ b/Pipes/AbstractPipes.php
@@ -105,7 +105,7 @@ protected function write(): ?array
} elseif (!isset($this->inputBuffer[0])) {
if (!\is_string($input)) {
if (!\is_scalar($input)) {
- throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', \get_class($this->input), \gettype($input)));
+ throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input)));
}
$input = (string) $input;
}
diff --git a/Pipes/UnixPipes.php b/Pipes/UnixPipes.php
index 58a8da07..5a0e9d47 100644
--- a/Pipes/UnixPipes.php
+++ b/Pipes/UnixPipes.php
@@ -35,10 +35,7 @@ public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveRea
parent::__construct($input);
}
- /**
- * @return array
- */
- public function __sleep()
+ public function __sleep(): array
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
diff --git a/Pipes/WindowsPipes.php b/Pipes/WindowsPipes.php
index 69768f3d..bca84f57 100644
--- a/Pipes/WindowsPipes.php
+++ b/Pipes/WindowsPipes.php
@@ -88,10 +88,7 @@ public function __construct($input, bool $haveReadSupport)
parent::__construct($input);
}
- /**
- * @return array
- */
- public function __sleep()
+ public function __sleep(): array
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
diff --git a/Process.php b/Process.php
index 09cd9602..b47ecca1 100644
--- a/Process.php
+++ b/Process.php
@@ -27,6 +27,8 @@
*
* @author Fabien Potencier
* @author Romain Neutron
+ *
+ * @implements \IteratorAggregate
*/
class Process implements \IteratorAggregate
{
@@ -71,6 +73,7 @@ class Process implements \IteratorAggregate
private $incrementalErrorOutputOffset = 0;
private $tty = false;
private $pty;
+ private $options = ['suppress_errors' => true, 'bypass_shell' => true];
private $useFileHandles = false;
/** @var PipesInterface */
@@ -137,16 +140,12 @@ class Process implements \IteratorAggregate
*
* @throws LogicException When proc_open is not installed
*/
- public function __construct($command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
+ public function __construct(array $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
{
if (!\function_exists('proc_open')) {
throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
}
- if (!\is_array($command)) {
- @trigger_error(sprintf('Passing a command as string when creating a "%s" instance is deprecated since Symfony 4.2, pass it as an array of its arguments instead, or use the "Process::fromShellCommandline()" constructor if you need features provided by the shell.', __CLASS__), \E_USER_DEPRECATED);
- }
-
$this->commandline = $command;
$this->cwd = $cwd;
@@ -213,7 +212,11 @@ public function __wakeup()
public function __destruct()
{
- $this->stop(0);
+ if ($this->options['create_new_console'] ?? false) {
+ $this->processPipes->close();
+ } else {
+ $this->stop(0);
+ }
}
public function __clone()
@@ -320,10 +323,7 @@ public function start(callable $callback = null, array $env = [])
$commandline = $this->replacePlaceholders($commandline, $env);
}
- $options = ['suppress_errors' => true];
-
if ('\\' === \DIRECTORY_SEPARATOR) {
- $options['bypass_shell'] = true;
$commandline = $this->prepareWindowsCommandLine($commandline, $env);
} elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
@@ -349,7 +349,7 @@ public function start(callable $callback = null, array $env = [])
throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
}
- $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $options);
+ $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
if (!\is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
@@ -511,7 +511,7 @@ public function getPid()
* @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
* @throws RuntimeException In case of failure
*/
- public function signal($signal)
+ public function signal(int $signal)
{
$this->doSignal($signal, true);
@@ -532,7 +532,7 @@ public function disableOutput()
throw new RuntimeException('Disabling output while the process is running is not possible.');
}
if (null !== $this->idleTimeout) {
- throw new LogicException('Output can not be disabled while an idle timeout is set.');
+ throw new LogicException('Output cannot be disabled while an idle timeout is set.');
}
$this->outputDisabled = true;
@@ -571,7 +571,7 @@ public function isOutputDisabled()
/**
* Returns the current output of the process (STDOUT).
*
- * @return string The process output
+ * @return string
*
* @throws LogicException in case the output has been disabled
* @throws LogicException In case the process is not started
@@ -593,7 +593,7 @@ public function getOutput()
* In comparison with the getOutput method which always return the whole
* output, this one returns the new output since the last call.
*
- * @return string The process output since the last call
+ * @return string
*
* @throws LogicException in case the output has been disabled
* @throws LogicException In case the process is not started
@@ -617,13 +617,13 @@ public function getIncrementalOutput()
*
* @param int $flags A bit field of Process::ITER_* flags
*
+ * @return \Generator
+ *
* @throws LogicException in case the output has been disabled
* @throws LogicException In case the process is not started
- *
- * @return \Generator
*/
#[\ReturnTypeWillChange]
- public function getIterator($flags = 0)
+ public function getIterator(int $flags = 0)
{
$this->readPipesForOutput(__FUNCTION__, false);
@@ -687,7 +687,7 @@ public function clearOutput()
/**
* Returns the current error output of the process (STDERR).
*
- * @return string The process error output
+ * @return string
*
* @throws LogicException in case the output has been disabled
* @throws LogicException In case the process is not started
@@ -710,7 +710,7 @@ public function getErrorOutput()
* whole error output, this one returns the new error output since the last
* call.
*
- * @return string The process error output since the last call
+ * @return string
*
* @throws LogicException in case the output has been disabled
* @throws LogicException In case the process is not started
@@ -778,7 +778,7 @@ public function getExitCodeText()
/**
* Checks if the process ended successfully.
*
- * @return bool true if the process ended successfully, false otherwise
+ * @return bool
*/
public function isSuccessful()
{
@@ -816,7 +816,7 @@ public function getTermSignal()
$this->requireProcessIsTerminated(__FUNCTION__);
if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
- throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
+ throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal cannot be retrieved.');
}
return $this->processInformation['termsig'];
@@ -857,7 +857,7 @@ public function getStopSignal()
/**
* Checks if the process is currently running.
*
- * @return bool true if the process is currently running, false otherwise
+ * @return bool
*/
public function isRunning()
{
@@ -873,7 +873,7 @@ public function isRunning()
/**
* Checks if the process has been started with no regard to the current state.
*
- * @return bool true if status is ready, false otherwise
+ * @return bool
*/
public function isStarted()
{
@@ -883,7 +883,7 @@ public function isStarted()
/**
* Checks if the process is terminated.
*
- * @return bool true if process is terminated, false otherwise
+ * @return bool
*/
public function isTerminated()
{
@@ -897,7 +897,7 @@ public function isTerminated()
*
* The status is one of: ready, started, terminated.
*
- * @return string The current process status
+ * @return string
*/
public function getStatus()
{
@@ -910,11 +910,11 @@ public function getStatus()
* Stops the process.
*
* @param int|float $timeout The timeout in seconds
- * @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
+ * @param int|null $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
*
* @return int|null The exit-code of the process or null if it's not running
*/
- public function stop($timeout = 10, $signal = null)
+ public function stop(float $timeout = 10, int $signal = null)
{
$timeoutMicro = microtime(true) + $timeout;
if ($this->isRunning()) {
@@ -982,7 +982,7 @@ public function getLastOutputTime(): ?float
/**
* Gets the command line to be executed.
*
- * @return string The command to execute
+ * @return string
*/
public function getCommandLine()
{
@@ -990,27 +990,9 @@ public function getCommandLine()
}
/**
- * Sets the command line to be executed.
+ * Gets the process timeout in seconds (max. runtime).
*
- * @param string|array $commandline The command to execute
- *
- * @return $this
- *
- * @deprecated since Symfony 4.2.
- */
- public function setCommandLine($commandline)
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
-
- $this->commandline = $commandline;
-
- return $this;
- }
-
- /**
- * Gets the process timeout (max. runtime).
- *
- * @return float|null The timeout in seconds or null if it's disabled
+ * @return float|null
*/
public function getTimeout()
{
@@ -1018,9 +1000,9 @@ public function getTimeout()
}
/**
- * Gets the process idle timeout (max. time since last output).
+ * Gets the process idle timeout in seconds (max. time since last output).
*
- * @return float|null The timeout in seconds or null if it's disabled
+ * @return float|null
*/
public function getIdleTimeout()
{
@@ -1032,13 +1014,11 @@ public function getIdleTimeout()
*
* To disable the timeout, set this value to null.
*
- * @param int|float|null $timeout The timeout in seconds
- *
* @return $this
*
* @throws InvalidArgumentException if the timeout is negative
*/
- public function setTimeout($timeout)
+ public function setTimeout(?float $timeout)
{
$this->timeout = $this->validateTimeout($timeout);
@@ -1046,21 +1026,19 @@ public function setTimeout($timeout)
}
/**
- * Sets the process idle timeout (max. time since last output).
+ * Sets the process idle timeout (max. time since last output) in seconds.
*
* To disable the timeout, set this value to null.
*
- * @param int|float|null $timeout The timeout in seconds
- *
* @return $this
*
* @throws LogicException if the output is disabled
* @throws InvalidArgumentException if the timeout is negative
*/
- public function setIdleTimeout($timeout)
+ public function setIdleTimeout(?float $timeout)
{
if (null !== $timeout && $this->outputDisabled) {
- throw new LogicException('Idle timeout can not be set while the output is disabled.');
+ throw new LogicException('Idle timeout cannot be set while the output is disabled.');
}
$this->idleTimeout = $this->validateTimeout($timeout);
@@ -1071,13 +1049,11 @@ public function setIdleTimeout($timeout)
/**
* Enables or disables the TTY mode.
*
- * @param bool $tty True to enabled and false to disable
- *
* @return $this
*
* @throws RuntimeException In case the TTY mode is not supported
*/
- public function setTty($tty)
+ public function setTty(bool $tty)
{
if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
throw new RuntimeException('TTY mode is not supported on Windows platform.');
@@ -1087,7 +1063,7 @@ public function setTty($tty)
throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
}
- $this->tty = (bool) $tty;
+ $this->tty = $tty;
return $this;
}
@@ -1095,7 +1071,7 @@ public function setTty($tty)
/**
* Checks if the TTY mode is enabled.
*
- * @return bool true if the TTY mode is enabled, false otherwise
+ * @return bool
*/
public function isTty()
{
@@ -1105,13 +1081,11 @@ public function isTty()
/**
* Sets PTY mode.
*
- * @param bool $bool
- *
* @return $this
*/
- public function setPty($bool)
+ public function setPty(bool $bool)
{
- $this->pty = (bool) $bool;
+ $this->pty = $bool;
return $this;
}
@@ -1129,7 +1103,7 @@ public function isPty()
/**
* Gets the working directory.
*
- * @return string|null The current working directory or null on failure
+ * @return string|null
*/
public function getWorkingDirectory()
{
@@ -1145,11 +1119,9 @@ public function getWorkingDirectory()
/**
* Sets the current working directory.
*
- * @param string $cwd The new working directory
- *
* @return $this
*/
- public function setWorkingDirectory($cwd)
+ public function setWorkingDirectory(string $cwd)
{
$this->cwd = $cwd;
@@ -1159,7 +1131,7 @@ public function setWorkingDirectory($cwd)
/**
* Gets the environment variables.
*
- * @return array The current environment variables
+ * @return array
*/
public function getEnv()
{
@@ -1183,7 +1155,7 @@ public function setEnv(array $env)
/**
* Gets the Process input.
*
- * @return resource|string|\Iterator|null The Process input
+ * @return resource|string|\Iterator|null
*/
public function getInput()
{
@@ -1204,7 +1176,7 @@ public function getInput()
public function setInput($input)
{
if ($this->isRunning()) {
- throw new LogicException('Input can not be set while the process is running.');
+ throw new LogicException('Input cannot be set while the process is running.');
}
$this->input = ProcessUtils::validateInput(__METHOD__, $input);
@@ -1212,26 +1184,6 @@ public function setInput($input)
return $this;
}
- /**
- * Sets whether environment variables will be inherited or not.
- *
- * @param bool $inheritEnv
- *
- * @return $this
- *
- * @deprecated since Symfony 4.4, env variables are always inherited
- */
- public function inheritEnvironmentVariables($inheritEnv = true)
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, env variables are always inherited.', __METHOD__), \E_USER_DEPRECATED);
-
- if (!$inheritEnv) {
- throw new InvalidArgumentException('Not inheriting environment variables is not supported.');
- }
-
- return $this;
- }
-
/**
* Performs a check between the timeout definition and the time the process started.
*
@@ -1259,6 +1211,44 @@ public function checkTimeout()
}
}
+ /**
+ * @throws LogicException in case process is not started
+ */
+ public function getStartTime(): float
+ {
+ if (!$this->isStarted()) {
+ throw new LogicException('Start time is only available after process start.');
+ }
+
+ return $this->starttime;
+ }
+
+ /**
+ * Defines options to pass to the underlying proc_open().
+ *
+ * @see https://php.net/proc_open for the options supported by PHP.
+ *
+ * Enabling the "create_new_console" option allows a subprocess to continue
+ * to run after the main process exited, on both Windows and *nix
+ */
+ public function setOptions(array $options)
+ {
+ if ($this->isRunning()) {
+ throw new RuntimeException('Setting options while the process is running is not possible.');
+ }
+
+ $defaultOptions = $this->options;
+ $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console'];
+
+ foreach ($options as $key => $value) {
+ if (!\in_array($key, $existingOptions)) {
+ $this->options = $defaultOptions;
+ throw new LogicException(sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions)));
+ }
+ $this->options[$key] = $value;
+ }
+ }
+
/**
* Returns whether TTY is supported on the current operating system.
*/
@@ -1318,7 +1308,7 @@ private function getDescriptors(): array
*
* @param callable|null $callback The user defined PHP callback
*
- * @return \Closure A PHP closure
+ * @return \Closure
*/
protected function buildCallback(callable $callback = null)
{
@@ -1346,7 +1336,7 @@ protected function buildCallback(callable $callback = null)
*
* @param bool $blocking Whether to use a blocking read call
*/
- protected function updateStatus($blocking)
+ protected function updateStatus(bool $blocking)
{
if (self::STATUS_STARTED !== $this->status) {
return;
@@ -1509,7 +1499,7 @@ private function doSignal(int $signal, bool $throwException): bool
{
if (null === $pid = $this->getPid()) {
if ($throwException) {
- throw new LogicException('Can not send signal on a non running process.');
+ throw new LogicException('Cannot send signal on a non running process.');
}
return false;
diff --git a/ProcessUtils.php b/ProcessUtils.php
index 121693ba..2a7aff71 100644
--- a/ProcessUtils.php
+++ b/ProcessUtils.php
@@ -35,11 +35,11 @@ private function __construct()
* @param string $caller The name of method call that validates the input
* @param mixed $input The input to validate
*
- * @return mixed The validated input
+ * @return mixed
*
* @throws InvalidArgumentException In case the input is not valid
*/
- public static function validateInput($caller, $input)
+ public static function validateInput(string $caller, $input)
{
if (null !== $input) {
if (\is_resource($input)) {
diff --git a/README.md b/README.md
index afce5e45..8777de4a 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,17 @@ Process Component
The Process component executes commands in sub-processes.
+Sponsor
+-------
+
+The Process component for Symfony 5.4/6.0 is [backed][1] by [SensioLabs][2].
+
+As the creator of Symfony, SensioLabs supports companies using Symfony, with an
+offering encompassing consultancy, expertise, services, training, and technical
+assistance to ensure the success of web application development projects.
+
+Help Symfony by [sponsoring][3] its development!
+
Resources
---------
@@ -11,3 +22,7 @@ Resources
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
+
+[1]: https://symfony.com/backers
+[2]: https://sensiolabs.com
+[3]: https://symfony.com/sponsor
diff --git a/Tests/CreateNewConsoleTest.php b/Tests/CreateNewConsoleTest.php
new file mode 100644
index 00000000..4d43fb8d
--- /dev/null
+++ b/Tests/CreateNewConsoleTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Process\Process;
+
+/**
+ * @author Andrei Olteanu
+ */
+class CreateNewConsoleTest extends TestCase
+{
+ public function testOptionCreateNewConsole()
+ {
+ $this->expectNotToPerformAssertions();
+ try {
+ $process = new Process(['php', __DIR__.'/ThreeSecondProcess.php']);
+ $process->setOptions(['create_new_console' => true]);
+ $process->disableOutput();
+ $process->start();
+ } catch (\Exception $e) {
+ $this->fail($e);
+ }
+ }
+
+ public function testItReturnsFastAfterStart()
+ {
+ // The started process must run in background after the main has finished but that can't be tested with PHPUnit
+ $startTime = microtime(true);
+ $process = new Process(['php', __DIR__.'/ThreeSecondProcess.php']);
+ $process->setOptions(['create_new_console' => true]);
+ $process->disableOutput();
+ $process->start();
+ $this->assertLessThan(3000, $startTime - microtime(true));
+ }
+}
diff --git a/Tests/ProcessFailedExceptionTest.php b/Tests/ProcessFailedExceptionTest.php
index d6d7bfb0..259ffd63 100644
--- a/Tests/ProcessFailedExceptionTest.php
+++ b/Tests/ProcessFailedExceptionTest.php
@@ -25,7 +25,7 @@ class ProcessFailedExceptionTest extends TestCase
*/
public function testProcessFailedExceptionThrowsException()
{
- $process = $this->getMockBuilder(Process::class)->setMethods(['isSuccessful'])->setConstructorArgs([['php']])->getMock();
+ $process = $this->getMockBuilder(Process::class)->onlyMethods(['isSuccessful'])->setConstructorArgs([['php']])->getMock();
$process->expects($this->once())
->method('isSuccessful')
->willReturn(true);
@@ -49,7 +49,7 @@ public function testProcessFailedExceptionPopulatesInformationFromProcessOutput(
$errorOutput = 'FATAL: Unexpected error';
$workingDirectory = getcwd();
- $process = $this->getMockBuilder(Process::class)->setMethods(['isSuccessful', 'getOutput', 'getErrorOutput', 'getExitCode', 'getExitCodeText', 'isOutputDisabled', 'getWorkingDirectory'])->setConstructorArgs([[$cmd]])->getMock();
+ $process = $this->getMockBuilder(Process::class)->onlyMethods(['isSuccessful', 'getOutput', 'getErrorOutput', 'getExitCode', 'getExitCodeText', 'isOutputDisabled', 'getWorkingDirectory'])->setConstructorArgs([[$cmd]])->getMock();
$process->expects($this->once())
->method('isSuccessful')
->willReturn(false);
@@ -97,7 +97,7 @@ public function testDisabledOutputInFailedExceptionDoesNotPopulateOutput()
$exitText = 'General error';
$workingDirectory = getcwd();
- $process = $this->getMockBuilder(Process::class)->setMethods(['isSuccessful', 'isOutputDisabled', 'getExitCode', 'getExitCodeText', 'getOutput', 'getErrorOutput', 'getWorkingDirectory'])->setConstructorArgs([[$cmd]])->getMock();
+ $process = $this->getMockBuilder(Process::class)->onlyMethods(['isSuccessful', 'isOutputDisabled', 'getExitCode', 'getExitCodeText', 'getOutput', 'getErrorOutput', 'getWorkingDirectory'])->setConstructorArgs([[$cmd]])->getMock();
$process->expects($this->once())
->method('isSuccessful')
->willReturn(false);
diff --git a/Tests/ProcessTest.php b/Tests/ProcessTest.php
index 74c662fb..790167fc 100644
--- a/Tests/ProcessTest.php
+++ b/Tests/ProcessTest.php
@@ -276,7 +276,7 @@ public function testLiveStreamAsInput()
public function testSetInputWhileRunningThrowsAnException()
{
$this->expectException(LogicException::class);
- $this->expectExceptionMessage('Input can not be set while the process is running.');
+ $this->expectExceptionMessage('Input cannot be set while the process is running.');
$process = $this->getProcessForCode('sleep(30);');
$process->start();
try {
@@ -301,7 +301,7 @@ public function testInvalidInput($value)
$process->setInput($value);
}
- public function provideInvalidInputValues()
+ public static function provideInvalidInputValues()
{
return [
[[]],
@@ -319,7 +319,7 @@ public function testValidInput($expected, $value)
$this->assertSame($expected, $process->getInput());
}
- public function provideInputValues()
+ public static function provideInputValues()
{
return [
[null, null],
@@ -328,7 +328,7 @@ public function provideInputValues()
];
}
- public function chainedCommandsOutputProvider()
+ public static function chainedCommandsOutputProvider()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
return [
@@ -422,7 +422,7 @@ public function testIncrementalOutput($getOutput, $getIncrementalOutput, $uri)
fclose($h);
}
- public function provideIncrementalOutput()
+ public static function provideIncrementalOutput()
{
return [
['getOutput', 'getIncrementalOutput', 'php://stdout'],
@@ -939,7 +939,7 @@ public function testExitCodeIsAvailableAfterSignal()
public function testSignalProcessNotRunning()
{
$this->expectException(LogicException::class);
- $this->expectExceptionMessage('Can not send signal on a non running process.');
+ $this->expectExceptionMessage('Cannot send signal on a non running process.');
$process = $this->getProcess('foo');
$process->signal(1); // SIGHUP
}
@@ -957,7 +957,7 @@ public function testMethodsThatNeedARunningProcess($method)
$process->{$method}();
}
- public function provideMethodsThatNeedARunningProcess()
+ public static function provideMethodsThatNeedARunningProcess()
{
return [
['getOutput'],
@@ -988,7 +988,7 @@ public function testMethodsThatNeedATerminatedProcess($method)
throw $e;
}
- public function provideMethodsThatNeedATerminatedProcess()
+ public static function provideMethodsThatNeedATerminatedProcess()
{
return [
['hasBeenSignaled'],
@@ -1058,7 +1058,7 @@ public function testEnableOrDisableOutputAfterRunDoesNotThrowException()
public function testDisableOutputWhileIdleTimeoutIsSet()
{
$this->expectException(LogicException::class);
- $this->expectExceptionMessage('Output can not be disabled while an idle timeout is set.');
+ $this->expectExceptionMessage('Output cannot be disabled while an idle timeout is set.');
$process = $this->getProcess('foo');
$process->setIdleTimeout(1);
$process->disableOutput();
@@ -1067,7 +1067,7 @@ public function testDisableOutputWhileIdleTimeoutIsSet()
public function testSetIdleTimeoutWhileOutputIsDisabled()
{
$this->expectException(LogicException::class);
- $this->expectExceptionMessage('timeout can not be set while the output is disabled.');
+ $this->expectExceptionMessage('timeout cannot be set while the output is disabled.');
$process = $this->getProcess('foo');
$process->disableOutput();
$process->setIdleTimeout(1);
@@ -1093,7 +1093,7 @@ public function testGetOutputWhileDisabled($fetchMethod)
$p->{$fetchMethod}();
}
- public function provideOutputFetchingMethods()
+ public static function provideOutputFetchingMethods()
{
return [
['getOutput'],
@@ -1130,7 +1130,7 @@ public function testTermSignalTerminatesProcessCleanly()
$this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException');
}
- public function responsesCodeProvider()
+ public static function responsesCodeProvider()
{
return [
// expected output / getter / code to execute
@@ -1140,7 +1140,7 @@ public function responsesCodeProvider()
];
}
- public function pipesCodeProvider()
+ public static function pipesCodeProvider()
{
$variations = [
'fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);',
@@ -1183,7 +1183,7 @@ public function testIncrementalOutputDoesNotRequireAnotherCall($stream, $method)
$process->stop();
}
- public function provideVariousIncrementals()
+ public static function provideVariousIncrementals()
{
return [
['php://stdout', 'getIncrementalOutput'],
@@ -1449,7 +1449,7 @@ public function testRawCommandLine()
$this->assertSame($expected, str_replace('Standard input code', '-', $p->getOutput()));
}
- public function provideEscapeArgument()
+ public static function provideEscapeArgument()
{
yield ['a"b%c%'];
yield ['a"b^c^'];
diff --git a/Tests/ThreeSecondProcess.php b/Tests/ThreeSecondProcess.php
new file mode 100644
index 00000000..e483b4b9
--- /dev/null
+++ b/Tests/ThreeSecondProcess.php
@@ -0,0 +1,14 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+echo 'Worker started';
+sleep(3);
+echo 'Worker done';
diff --git a/composer.json b/composer.json
index c0f7599f..1669eba5 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,7 @@
}
],
"require": {
- "php": ">=7.1.3",
+ "php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"autoload": {