Alpha ZealPHP is early-stage and under active development. APIs may change between minor versions until v1.0. Feedback and bug reports welcome on GitHub.
API Index — Namespaces, Packages, Reports, Indices

CLI
in package

Command-line interface handling for the ZealPHP server lifecycle (start/stop/restart/status/logs + PID-file management).

Extracted verbatim from App.php (Phase 1 of the App.php decomposition). Every method here was previously a private/protected static on App and is only reached internally — there are no public-API BC shims because the CLI surface is the php app.php … command path, not App::cli*() calls.

Table of Contents

Methods

claimOrphanIfAny()  : bool
Recover from an orphaned-daemon situation: pid file missing or stale but the port is still held. If the listener is a ZealPHP process, graceful-then-force kill it. Returns true when an orphan was cleaned up, false when there's nothing to do (port free, or held by something that isn't ours).
parseCliArgs()  : array<string, mixed>
Parse $argv, execute any lifecycle sub-command, and return server-config overrides.
processIsZealphp()  : bool
True when /proc/$pid/cmdline looks like a ZealPHP daemon: argv[0] is a real php binary (php, php8.3, etc.) AND the args reference app.php.
resolvePidFile()  : string
Resolve the PID file path for the given CLI flags.
cliHelp()  : void
Print the php app.php --help usage text to stdout and return.
cliLogs()  : void
cliStatus()  : void
cliStatusOne()  : void
cliStop()  : void
Stop the server identified by $pidFile.
cliStopAuto()  : void
Stop all running ZealPHP instances when no specific port is given.
ensurePidDir()  : void
Ensure $dir exists and is writable, creating it recursively if needed.
extractPortFromPidFile()  : int
Pull the port number from a default-shaped pid file path like /tmp/zealphp/zealphp_8080.pid. Returns 0 when the caller passed a --pid-file override that doesn't match the convention.
findPortOwnerPid()  : int|null
Returns the PID listening on $port, or null when nothing's listening or it can't be determined (non-Linux, /proc unreadable). Linux-only: /proc/net/tcp + tcp6 give the LISTEN-state socket inode; /proc/[pid]/fd/* resolves inode → owner pid. We deliberately avoid stream_socket_server / socket_bind here — those are intercepted by OpenSwoole's runtime hook (HOOK_ALL) and become coroutine-only, which would crash this CLI path.
forkStartupReporter()  : void
For daemonized start/restart: fork so the terminal-attached parent polls for the new daemon's PID file and prints a confirmation line BEFORE the shell prompt returns, while the child goes on to boot the (self-daemonizing) server. The parent never touches OpenSwoole — it only watches the PID file and exits, so the confirmation is always the last thing written to the terminal (fixes the issue #17 race where the prompt returned first and the message overlapped the next command).

Methods

claimOrphanIfAny()

Recover from an orphaned-daemon situation: pid file missing or stale but the port is still held. If the listener is a ZealPHP process, graceful-then-force kill it. Returns true when an orphan was cleaned up, false when there's nothing to do (port free, or held by something that isn't ours).

public static claimOrphanIfAny(int $port) : bool

Orphan recovery is rare and notable, so messages always print even when called from a "quiet" code path (cliStop during restart) — silent recovery hides the fact that the system was in a degraded state that needed self-healing.

Parameters
$port : int
Return values
bool

parseCliArgs()

Parse $argv, execute any lifecycle sub-command, and return server-config overrides.

public static parseCliArgs() : array<string, mixed>

Sub-commands (stop, status, logs, restart) are handled in-process and call exit() when done. The start / default path returns an array of OpenSwoole $server->set() override keys (_host, _port, worker_num, daemonize, etc.) that App::run() merges into its config. Returns an empty array when no overrides are needed.

Return values
array<string, mixed>

processIsZealphp()

True when /proc/$pid/cmdline looks like a ZealPHP daemon: argv[0] is a real php binary (php, php8.3, etc.) AND the args reference app.php.

public static processIsZealphp(int $pid) : bool

Used to gate kill operations so a recycled PID belonging to an unrelated process is never targeted.

The stricter argv[0] check matters because bash wrappers that spawn php app.php … as a child carry "app.php" in their own cmdline — a naive substring match falsely identifies them as ZealPHP daemons and would happily kill them.

Non-Linux returns true (be permissive — caller still has posix_kill).

Parameters
$pid : int
Return values
bool

resolvePidFile()

Resolve the PID file path for the given CLI flags.

public static resolvePidFile(array<string, mixed> $flags) : string

Resolution order (first match wins):

  1. --pid-file flag ($flags['pid_file']).
  2. ZEALPHP_PID_FILE environment variable.
  3. ZEALPHP_LOG_DIR env var + zealphp_{port}.pid.
  4. resolve_log_dir() result (per-user fallback) + zealphp_{port}.pid.

Creates the parent directory when it does not exist.

Parameters
$flags : array<string, mixed>

Parsed CLI flags from parseCliArgs().

Return values
string

cliHelp()

Print the php app.php --help usage text to stdout and return.

private static cliHelp() : void

The caller is responsible for calling exit(0) after this.

cliLogs()

private static cliLogs(array<string, mixed> $flags) : void
Parameters
$flags : array<string, mixed>

cliStatus()

private static cliStatus(array<string, mixed> $flags) : void
Parameters
$flags : array<string, mixed>

cliStatusOne()

private static cliStatusOne(string $pidFile) : void
Parameters
$pidFile : string

cliStop()

Stop the server identified by $pidFile.

private static cliStop(string $pidFile[, bool $quiet = false ]) : void

Sends SIGTERM to the process group (or PID), polls up to 10 s for graceful shutdown, then falls back to SIGKILL. Removes the PID file on success. When the PID file is missing or stale, calls claimOrphanIfAny() to handle a running-but-unregistered daemon. Output is suppressed when $quiet is true.

Parameters
$pidFile : string
$quiet : bool = false

cliStopAuto()

Stop all running ZealPHP instances when no specific port is given.

private static cliStopAuto() : void

Globs {logDir}/zealphp_*.pid, verifies each PID with processIsZealphp(), and stops the lone instance automatically. When multiple instances are found, lists them and asks the user to specify a port with -p PORT.

ensurePidDir()

Ensure $dir exists and is writable, creating it recursively if needed.

private static ensurePidDir(string $dir) : void

Logs a warning via elog() when creation fails — never throws.

Parameters
$dir : string

extractPortFromPidFile()

Pull the port number from a default-shaped pid file path like /tmp/zealphp/zealphp_8080.pid. Returns 0 when the caller passed a --pid-file override that doesn't match the convention.

private static extractPortFromPidFile(string $pidFile) : int
Parameters
$pidFile : string
Return values
int

findPortOwnerPid()

Returns the PID listening on $port, or null when nothing's listening or it can't be determined (non-Linux, /proc unreadable). Linux-only: /proc/net/tcp + tcp6 give the LISTEN-state socket inode; /proc/[pid]/fd/* resolves inode → owner pid. We deliberately avoid stream_socket_server / socket_bind here — those are intercepted by OpenSwoole's runtime hook (HOOK_ALL) and become coroutine-only, which would crash this CLI path.

private static findPortOwnerPid(int $port) : int|null
Parameters
$port : int
Return values
int|null

forkStartupReporter()

For daemonized start/restart: fork so the terminal-attached parent polls for the new daemon's PID file and prints a confirmation line BEFORE the shell prompt returns, while the child goes on to boot the (self-daemonizing) server. The parent never touches OpenSwoole — it only watches the PID file and exits, so the confirmation is always the last thing written to the terminal (fixes the issue #17 race where the prompt returned first and the message overlapped the next command).

private static forkStartupReporter(string $pidFile, int $port, string $verb) : void

No-op when pcntl is unavailable or the fork fails: start proceeds without a confirmation line (prior behaviour), never silently broken.

Parameters
$pidFile : string
$port : int
$verb : string

e.g. "Restarted" or "Started ZealPHP in detached mode"

Forks + polls the daemon PID file and exits in the child — neither unit-testable in-process (pcntl_fork/exit kills the test runner) nor dumpable as a subprocess (the OpenSwoole server suppresses the PHP shutdown coverage flush). Verified manually + by the CLI behaviour.

Tags
codeCoverageIgnore
On this page