Is $argv implicitly immutable across script-files or do I have another error in my way of thinking?
That depends on how the script/utility works that you try to invoke. Which means you can't expect it to work stable and I would refrain from it unless you know it has this interface. As you don't know it - otherwise you would not ask the question that way - throw that idea into the bin in this case.
I assume creating a new shell by shell_exec() takes some time.
This may be (we can't look into your system configuration), but if it is a linux system this is very likely not the case.
In practice, the use of a new shell sub-process to invoke the tooling is the much, much better way to do things here. This is also how composer(1) invokes scripts (see Scripts) - unless they are bound as (static) methods - and is always true for the composer exec command.
The reason is that you can control not only the command line arguments much better but also the working directory and the environment parameters (a.k.a. environment variables or environment in short), compare proc_open(php). The standard streams are available as well.
As you're running in context of composer, and if you have access to the sources of it (e.g. you bind a composer script or hook in your composer.json configuration), you can use the process components that ship with composer itself (its all PHP), it has quite some utility in there.
If you just want to start lightly, I found the passthru(php) function a good fit for quickly getting started:
// the command you'd like to execute
$command = '/path/to/vendor/bin/php-cs-fixer';
$args = [
'fix',
'--config',
'/path/to/.php-cs-fixer.php',
'/path/to/project'
];
// build the command-line
$commandLine = sprintf(
'%s %s',
$command,
implode(' ', array_map('escapeshellarg', $args))
);
// execute
$result = passthru($commandLine, $exitStatus);
// be verbose and give some debug info
fprintf(
STDERR,
"debug: command %s exited with status %d\n",
$commandLine,
$exitStatus
);
// throw on exit status != 0, a convention only but you often want this
if (false === $result || $existStatus !== 0) {
throw new \RuntimeException(sprintf(
'command "%s" exited with non-zero status %d (result=%s).\n',
addcslashes($commandLine, "\0..\37\"\\\177..\377"),
$exitStatus,
var_export($result, true)
), (int)$exitStatus);
}