Files
nih-php-command-builder/src/Stdio.php
Jonas Kattendick 5797059008 fix!: handle php errors with custom error handling
This commit changes the api of the stream classes, since indication of
success or failure is no longer necessary.
2026-02-13 23:26:32 +01:00

122 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Nih\CommandBuilder;
use InvalidArgumentException;
use Override;
use Stringable;
/**
* Describes what to do with a standard I/O stream for a child process when
* passed to the stdin, stdout, and stderr methods of {@see Command}.
*
* @psalm-suppress UnusedClass
*/
abstract class Stdio
{
/**
* The child inherits from the corresponding parent descriptor.
*/
public static function inherit(): StdioInterface
{
return new class implements StdioInterface {
#[Override]
public function getDescriptionSpec(int $fd): mixed
{
return match ($fd) {
0 => STDIN,
1 => STDOUT,
2 => STDERR,
default => ['php://fd/' . $fd, 'w+'],
};
}
};
}
/**
* A new pipe should be arranged to connect the parent and child processes.
*/
public static function piped(): StdioInterface
{
return new class implements StdioInterface {
#[Override]
public function getDescriptionSpec(int $fd): mixed
{
return match ($fd) {
0 => ['pipe', 'r'],
1, 2 => ['pipe', 'w'],
default => ['pipe', 'w+'],
};
}
};
}
/**
* This stream will be ignored. This is the equivalent of attaching the
* stream to `/dev/null`.
*/
public static function null(): StdioInterface
{
return new class implements StdioInterface {
#[Override]
public function getDescriptionSpec(int $fd): mixed
{
// TODO: Support windows (I think you just write to `nul` in any
// directory?)
return match ($fd) {
0 => ['file', '/dev/null', 'r'],
1, 2 => ['file', '/dev/null', 'w'],
default => ['file', '/dev/null', 'w+'],
};
}
};
}
/**
* Like piped, but instead of capturing the stream into a handle, read
* and/or write from/to a file.
*/
public static function file(string|Stringable $filename, string $mode): StdioInterface
{
return new class((string) $filename, $mode) implements StdioInterface {
public function __construct(
private string $filename,
private string $mode,
) {}
#[Override]
public function getDescriptionSpec(int $fd): mixed
{
return ['file', $this->filename, $this->mode];
}
};
}
/**
* Like piped, but instead of capturing the stream into a handle, read
* and/or write from/to a stream resource.
*
* @param resource $stream
*
* @throws InvalidArgumentException When stream is not a stream resource
*/
public static function stream($stream): StdioInterface
{
if (get_resource_type($stream) !== 'stream') {
throw new InvalidArgumentException('resource is not a stream');
}
return new class($stream) implements StdioInterface {
public function __construct(private mixed $stream) {}
#[Override]
public function getDescriptionSpec(int $fd): mixed
{
return $this->stream;
}
};
}
}