# PSL - PHP Standard Library PSL (PHP Standard Library) is a comprehensive standard library for PHP inspired by HHVM/HSL. It provides a consistent, centralized, well-typed set of APIs for common programming tasks including async/concurrent programming, collections manipulation, networking, I/O operations, cryptography, terminal UI, and type validation. PSL replaces PHP's built-in functions and primitives with safer, async-ready alternatives that error predictably through typed exceptions rather than returning false or requiring manual error checking. The library is built on top of RevoltPHP for async operations, making it compatible with Amphp and other libraries using the same event loop. PSL requires PHP 8.4+ and follows functional programming patterns with immutable data structures where appropriate. All functions have consistent argument ordering (iterable first, callback second), provide strong typing with generics support through static analyzers (Mago, Psalm, PHPStan), and throw specific exceptions instead of returning error values. ## Type Validation and Coercion The `Type` component implements runtime type validation using the "Parse, Don't Validate" pattern. It provides composable type combinators for validating untrusted input with detailed error paths for nested structures. ```php use Psl\Type; // Basic type coercion - converts string to int if possible $age = Type\int()->coerce("42"); // Returns: 42 // Type assertion - throws if value isn't already the correct type $name = Type\non_empty_string()->assert("Alice"); // Returns: "Alice" // Type matching - check without throwing $isValid = Type\non_empty_string()->matches($input); // Returns: bool // Complex shape validation with nested structures $userType = Type\shape([ 'name' => Type\string(), 'age' => Type\int(), 'tags' => Type\vec(Type\string()), 'profile' => Type\optional(Type\shape([ 'bio' => Type\string(), 'avatar' => Type\nullable(Type\string()), ])), ]); $validatedUser = $userType->coerce([ 'name' => 'Alice', 'age' => 30, 'tags' => ['developer', 'php'], ]); // Returns: array{name: string, age: int, tags: list, ...} // Union types - tries each type in order $idType = Type\union(Type\int(), Type\non_empty_string()); $id = $idType->coerce(123); // Returns: 123 // Sized integer types with range validation $port = Type\u16()->coerce(8080); // uint16: 0-65535 $score = Type\i8()->coerce(100); // int8: -128 to 127 ``` ## Async and Concurrent Programming The `Async` component enables concurrent programming using PHP fibers with structured concurrency. It provides combinators for running tasks in parallel, sequentially, or with concurrency limits. ```php use Psl\Async; use Psl\DateTime\Duration; use Psl\IO; // Entry point for async applications Async\main(static function(): int { // Run multiple tasks concurrently - returns results in original order $results = Async\concurrently([ static function(): string { Async\sleep(Duration::milliseconds(100)); return 'task 1 complete'; }, static function(): string { Async\sleep(Duration::milliseconds(50)); return 'task 2 complete'; }, ]); // $results = ['task 1 complete', 'task 2 complete'] // Run tasks sequentially $sequential = Async\series([ static fn() => 'first', static fn() => 'second', ]); // Fire and forget with error handling $awaitable = Async\run(static function(): void { // background work }); $awaitable->ignore(); // Suppress UnhandledAwaitableException if it fails // Await with transformation $result = Async\run(static fn() => 42) ->map(fn(int $n) => $n * 2) ->catch(fn(Throwable $e) => 0) ->await(); // Semaphore for concurrency limiting (max 3 concurrent) $semaphore = new Async\Semaphore(3, static function(string $url): string { return fetch_url($url); }); $results = Async\concurrently([ fn() => $semaphore->waitFor('https://api1.example.com'), fn() => $semaphore->waitFor('https://api2.example.com'), fn() => $semaphore->waitFor('https://api3.example.com'), fn() => $semaphore->waitFor('https://api4.example.com'), ]); return 0; }); ``` ## Vec - Sequential List Operations The `Vec` component provides functions for creating and transforming sequential, 0-indexed arrays (`list`). All Vec functions return re-indexed lists with consistent argument ordering. ```php use Psl\Vec; use Psl\Str; // Map: transform every element Vec\map([1, 2, 3], fn(int $n) => $n * 2); // Returns: [2, 4, 6] // Map with key access Vec\map_with_key(['a', 'b', 'c'], fn(int $i, string $v) => "{$i}:{$v}"); // Returns: ['0:a', '1:b', '2:c'] // Filter: keep elements matching predicate Vec\filter([1, 2, 3, 4, 5], fn(int $n) => $n > 3); // Returns: [4, 5] // Filter nulls from list Vec\filter_nulls([1, null, 3, null, 5]); // Returns: [1, 3, 5] // Sorting Vec\sort([3, 1, 4, 1, 5], fn($a, $b) => $a <=> $b); // Returns: [1, 1, 3, 4, 5] Vec\sort_by(['banana', 'apple', 'cherry'], fn(string $s) => Str\length($s)); // Returns: ['apple', 'banana', 'cherry'] // Combining Vec\concat([1, 2], [3, 4], [5]); // Returns: [1, 2, 3, 4, 5] Vec\flatten([[1, 2], [3, 4], [5]]); // Returns: [1, 2, 3, 4, 5] Vec\unique([1, 2, 2, 3, 3, 3]); // Returns: [1, 2, 3] // Generating Vec\range(1, 5); // Returns: [1, 2, 3, 4, 5] Vec\fill(3, 'x'); // Returns: ['x', 'x', 'x'] ``` ## Dict - Associative Array Operations The `Dict` component provides functions for creating and transforming associative arrays (`array`). Unlike Vec, Dict functions preserve keys. ```php use Psl\Dict; use Psl\Str; // Map values, preserve keys Dict\map(['a' => 1, 'b' => 2, 'c' => 3], fn(int $v) => $v * 10); // Returns: ['a' => 10, 'b' => 20, 'c' => 30] // Map keys Dict\map_keys(['a' => 1, 'b' => 2], fn(string $k) => Str\uppercase($k)); // Returns: ['A' => 1, 'B' => 2] // Filter with preserved keys Dict\filter(['a' => 1, 'b' => 2, 'c' => 3], fn(int $v) => $v > 1); // Returns: ['b' => 2, 'c' => 3] // Build dict from iterable with key and value selectors $users = [['id' => 1, 'name' => 'Alice'], ['id' => 2, 'name' => 'Bob']]; Dict\pull($users, fn($u) => $u['name'], fn($u) => $u['id']); // Returns: [1 => 'Alice', 2 => 'Bob'] // Group by key $items = ['apple', 'apricot', 'banana', 'blueberry']; Dict\group_by($items, fn(string $s) => $s[0]); // Returns: ['a' => ['apple', 'apricot'], 'b' => ['banana', 'blueberry']] // Merge multiple dicts (later values win) Dict\merge(['a' => 1, 'b' => 2], ['b' => 3, 'c' => 4]); // Returns: ['a' => 1, 'b' => 3, 'c' => 4] // Select specific keys Dict\select_keys(['a' => 1, 'b' => 2, 'c' => 3], ['a', 'c']); // Returns: ['a' => 1, 'c' => 3] ``` ## Iter - Iterator Operations The `Iter` component provides functions for working with iterables without materializing them into arrays. Useful for lazy evaluation and reducing memory usage. ```php use Psl\Iter; // Reduce to single value $sum = Iter\reduce([1, 2, 3, 4], fn(int $carry, int $v) => $carry + $v, 0); // Returns: 10 // Reduce with keys $cart = ['apple' => 2, 'banana' => 3]; $prices = ['apple' => 1.50, 'banana' => 0.75]; $total = Iter\reduce_with_keys( $cart, fn(float $total, string $item, int $qty) => $total + ($prices[$item] * $qty), 0.0 ); // Returns: 5.25 // Check predicates Iter\all([2, 4, 6], fn(int $n) => $n % 2 === 0); // true Iter\any([1, 2, 3], fn(int $n) => $n > 2); // true Iter\none([1, 2, 3], fn(int $n) => $n > 5); // true // Search $found = Iter\search(['a', 'b', 'c'], fn(string $s) => $s === 'b'); // Returns: 'b' or null // First/last Iter\first([1, 2, 3]); // 1 Iter\last([1, 2, 3]); // 3 // Count Iter\count([1, 2, 3, 4, 5]); // 5 ``` ## Str - Unicode String Operations The `Str` component provides Unicode-aware string functions with UTF-8 support by default. Three tiers: `Str\` (codepoints), `Str\Byte\` (raw bytes), `Str\Grapheme\` (visual units). ```php use Psl\Str; // Case transformation Str\uppercase('hello'); // 'HELLO' Str\lowercase('HELLO'); // 'hello' Str\capitalize('hello world'); // 'Hello world' Str\capitalize_words('hello world'); // 'Hello World' // Search and replace Str\replace('hello world', 'world', 'PHP'); // 'hello PHP' Str\replace_every('aabbcc', ['aa' => '1', 'cc' => '3']); // '1bb3' // String operations Str\reverse('Hello'); // 'olleH' Str\repeat('ab', 3); // 'ababab' Str\pad_left('42', 5, '0'); // '00042' // Searching Str\contains('hello world', 'world'); // true Str\starts_with('hello', 'he'); // true Str\ends_with('hello', 'lo'); // true Str\search('hello', 'l'); // 2 (position) // Slicing and splitting Str\slice('hello world', 0, 5); // 'hello' Str\split('a,b,c', ','); // ['a', 'b', 'c'] Str\chunk('hello', 2); // ['he', 'll', 'o'] // Trimming Str\trim(' hello '); // 'hello' Str\trim_left(' hello'); // 'hello' Str\trim_right('hello '); // 'hello' // Length (Unicode-aware) Str\length('cafe'); // 4 Str\length('cafe'); // 4 (4 codepoints) ``` ## JSON Encoding and Decoding The `Json` component provides JSON operations with typed exceptions and integration with the Type system for validated decoding. ```php use Psl\Json; use Psl\Type; // Encode with clean defaults (unescaped unicode/slashes) $json = Json\encode(['name' => 'Alice', 'emoji' => '🎉']); // Returns: '{"name":"Alice","emoji":"🎉"}' // Decode to mixed $data = Json\decode('{"key": "value"}'); // Returns: ['key' => 'value'] // Typed decoding with validation $user = Json\typed('{"name":"Alice","age":30}', Type\shape([ 'name' => Type\string(), 'age' => Type\int(), ])); // $user['name'] is string, $user['age'] is int - guaranteed // Decode list of integers $ids = Json\typed('[1, 2, 3]', Type\vec(Type\int())); // Returns: [1, 2, 3] as list // Invalid structure throws DecodeException with path try { Json\typed('{"name":"Alice"}', Type\shape([ 'name' => Type\string(), 'age' => Type\int(), // missing! ])); } catch (Json\Exception\DecodeException $e) { // Error includes path to failing field } ``` ## TCP Networking The `TCP` component provides non-blocking TCP client and server connections with connection pooling and retry support. ```php use Psl\Async; use Psl\TCP; use Psl\IO; Async\main(static function(): int { // Simple echo server and client $listener = TCP\listen('127.0.0.1', 8080); Async\concurrently([ 'server' => static function() use ($listener): void { $connection = $listener->accept(); $request = $connection->readAll(); $connection->writeAll("echo: {$request}"); $connection->close(); $listener->close(); }, 'client' => static function() use ($listener): void { $address = $listener->getLocalAddress(); $client = TCP\connect($address->host, $address->port ?? 0); $client->writeAll('hello'); $client->shutdown(); $response = $client->readAll(); IO\write_line('Response: %s', $response); $client->close(); }, ]); // Connection pooling for reuse $pool = new TCP\SocketPool( connector: new TCP\Connector(), idleTimeout: 60.0, maxConnectionsPerHost: 10, ); $conn1 = $pool->checkout('api.example.com', 443); // use connection... $pool->checkin($conn1); // Return for reuse return 0; }); ``` ## File Operations The `File` component provides typed file handles for reading and writing with automatic locking. The `Filesystem` component handles file/directory management. ```php use Psl\File; use Psl\Filesystem; use Psl\IO; // Quick read/write (auto-locks) File\write('/tmp/data.txt', '{"key": "value"}'); $content = File\read('/tmp/data.txt'); // Read with offset and length $header = File\read('/tmp/data.txt', offset: 0, length: 10); // Write modes File\write($path, 'content', File\WriteMode::Truncate); // Overwrite File\write($path, 'more', File\WriteMode::Append); // Append File\write($path, 'new', File\WriteMode::MustCreate); // Fail if exists // File handles for more control $handle = File\open_read_only('/tmp/data.txt'); $content = $handle->readAll(); $handle->close(); $writer = File\open_write_only('/tmp/output.txt', File\WriteMode::Truncate); $writer->writeAll('Hello'); $writer->close(); // Filesystem operations Filesystem\create_directory('/tmp/app/data', 0o755); Filesystem\create_file('/tmp/app/data/file.txt'); Filesystem\copy('/tmp/source.txt', '/tmp/dest.txt'); Filesystem\delete_file('/tmp/old.txt'); Filesystem\delete_directory('/tmp/app', recursive: true); // Checks Filesystem\exists('/tmp/file.txt'); // bool Filesystem\is_file('/tmp/file.txt'); // bool Filesystem\is_directory('/tmp/dir'); // bool Filesystem\is_readable('/tmp/file.txt'); // bool Filesystem\is_writable('/tmp/file.txt'); // bool // Temporary files $tmp = Filesystem\create_temporary_file(prefix: 'app_'); ``` ## Result Type The `Result` component represents computations that either succeeded or failed, enabling deferred error handling and batch processing without scattered try/catch blocks. ```php use Psl\Result; use Psl\Json; use Psl\Type; // Wrap a potentially failing operation $result = Result\wrap(static fn() => Json\typed( '{"name":"Alice"}', Type\dict(Type\string(), Type\string()) )); // Check outcome if ($result->isSucceeded()) { $data = $result->getResult(); } else { $error = $result->getThrowable(); } // Get value with fallback $data = $result->unwrapOr(['default' => 'value']); // Transform successful value $mapped = $result->map(fn(array $data) => $data['name']); // Recover from failure $recovered = $result->catch(fn(Throwable $e) => ['fallback']); // Handle both cases $output = $result->proceed( fn(array $data) => "Success: " . $data['name'], fn(Throwable $e) => "Error: " . $e->getMessage(), ); // Batch processing with statistics $results = [ Result\wrap(fn() => 'ok'), Result\wrap(fn() => throw new Exception('fail')), Result\wrap(fn() => 'also ok'), ]; $stats = Result\collect_stats($results); // $stats->successes: 2, $stats->failures: 1 // Convert throwing function to Result-returning function $safeParse = Result\reflect(fn(string $json) => Json\decode($json)); $result = $safeParse('invalid json'); // Returns Failure instead of throwing ``` ## Option Type The `Option` component represents values that may or may not be present, replacing nullable types with explicit Some/None semantics. ```php use Psl\Option; // Creating options $present = Option\some(42); $absent = Option\none(); // Bridge from nullable $option = Option\from_nullable($nullableValue); // Check and unwrap if ($present->isSome()) { $value = $present->unwrap(); // 42 } $value = $present->unwrapOr(0); // 42 (or default) $value = $absent->unwrapOr(0); // 0 // Transform $doubled = $present->map(fn(int $n) => $n * 2); // Some(84) $none = $absent->map(fn(int $n) => $n * 2); // None // Chain lookups (flatMap) $result = $present ->andThen(fn(int $n) => $n > 0 ? Option\some($n) : Option\none()) ->map(fn(int $n) => "positive: $n"); // Pattern matching $message = $option->proceed( fn(int $value) => "Found: $value", fn() => "Not found", ); // Filter $filtered = $present->filter(fn(int $n) => $n > 50); // None (42 < 50) // Side effects without changing option $option->apply(fn(int $n) => log("Value is $n")); ``` ## Symmetric Cryptography The `Crypto\Symmetric` component provides authenticated encryption using XChaCha20-Poly1305 with automatic nonce management. ```php use Psl\Crypto\Symmetric; use Psl\IO; // Generate a new secret key $key = Symmetric\generate_key(); // Encrypt (nonce is managed automatically) $ciphertext = Symmetric\seal('Hello, World!', $key); // Decrypt $plaintext = Symmetric\open($ciphertext, $key); // Returns: 'Hello, World!' // With additional authenticated data (AAD) $ciphertext = Symmetric\seal( 'secret message', $key, additional_data: 'user-id:123' // Not encrypted, but bound to ciphertext ); // Decryption fails if AAD doesn't match $plaintext = Symmetric\open($ciphertext, $key, additional_data: 'user-id:123'); // Stream encryption for large data $encryptor = new Symmetric\StreamEncryptor($key); $encrypted = ''; foreach ($dataChunks as $chunk) { $encrypted .= $encryptor->push($chunk); } $encrypted .= $encryptor->finalize(); $decryptor = new Symmetric\StreamDecryptor($key); $decrypted = ''; foreach ($encryptedChunks as $chunk) { $decrypted .= $decryptor->pull($chunk); } ``` ## Hash Functions The `Hash` component provides cryptographic and non-cryptographic hashing with timing-safe comparison and HMAC support. ```php use Psl\Hash; // Compute hash $sha256 = Hash\hash('Hello, World!', Hash\Algorithm::Sha256); // 'dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f' $md5 = Hash\hash('Hello, World!', Hash\Algorithm::Md5); // '65a8e27d8879283831b664bd8b7f0ad4' // Timing-safe comparison (prevents timing attacks) $isValid = Hash\equals($expectedHash, $providedHash); // HMAC for message authentication $hmac = Hash\Hmac\hash('message', 'secret-key', Hash\Hmac\Algorithm::Sha256); // Incremental hashing for large data $context = Hash\Context::forAlgorithm(Hash\Algorithm::Sha256); $context = $context->update('chunk 1'); $context = $context->update('chunk 2'); $finalHash = $context->finalize(); // HMAC incremental $hmacContext = Hash\Context::hmac(Hash\Hmac\Algorithm::Sha256, 'secret-key'); $hmacContext = $hmacContext->update('data'); $hmacHash = $hmacContext->finalize(); ``` ## Shell Command Execution The `Shell` component provides safe shell command execution with argument escaping, error output handling, and timeout support. ```php use Psl\Shell; use Psl\DateTime\Duration; use Psl\IO; // Basic command execution $output = Shell\execute('echo', ['Hello', 'World']); // Returns: 'Hello World' // With working directory $output = Shell\execute('ls', ['-la'], '/tmp'); // With environment variables $output = Shell\execute( 'php', ['-r', 'echo getenv("APP_ENV");'], environment: ['APP_ENV' => 'production'] ); // With timeout try { $output = Shell\execute( 'sleep', ['10'], timeout: Duration::seconds(2) ); } catch (Shell\Exception\TimeoutException $e) { IO\write_line('Command timed out'); } // Capture stderr with stdout $output = Shell\execute( 'some-command', [], error_output_behavior: Shell\ErrorOutputBehavior::Append ); // Handle execution errors try { Shell\execute('false', []); // Command that exits non-zero } catch (Shell\Exception\FailedExecutionException $e) { IO\write_line('Exit code: %d', $e->getCode()); IO\write_line('Output: %s', $e->getOutput()); IO\write_line('Stderr: %s', $e->getErrorOutput()); } ``` ## Process Management The `Process` component provides advanced process management with streaming I/O, signals, and non-blocking operations. ```php use Psl\Process\Command; use Psl\IO; // Run command and collect output $output = Command::create('echo') ->withArguments(['Hello', 'from', 'process']) ->output(); if ($output->status->isSuccessful()) { IO\write_line('Output: %s', trim($output->stdout)); } // Full process control $process = Command::create('cat') ->withStdin(Process\Stdio::piped()) ->withStdout(Process\Stdio::piped()) ->spawn(); $process->getStdin()->writeAll("Hello\n"); $process->getStdin()->close(); $result = $process->getStdout()->readAll(); $status = $process->wait(); // Shell commands (with shell interpretation) $output = Command::shell('echo $HOME | tr a-z A-Z')->output(); // With environment and working directory $output = Command::create('npm') ->withArguments(['run', 'build']) ->withWorkingDirectory('/app') ->withEnvironment(['NODE_ENV' => 'production']) ->output(); // Timeout $output = Command::create('long-running-task') ->output(timeout: Duration::seconds(30)); ``` ## DateTime Operations The `DateTime` component provides immutable, timezone-aware date and time types with Duration and Period support. ```php use Psl\DateTime; use Psl\IO; // Current time $now = DateTime\DateTime::now(); $tokyo = DateTime\DateTime::now(DateTime\Timezone::AsiaTokyo); // From components $birthday = DateTime\DateTime::fromParts( DateTime\Timezone::AmericaNewYork, 1990, DateTime\Month::March, 15, 14, 30, 0 ); // Duration (exact time spans) $timeout = DateTime\Duration::seconds(30); $twoHours = DateTime\Duration::hours(2); $precise = DateTime\Duration::milliseconds(1500); // Normalizes to 1s 500ms // Date arithmetic $later = $now->plus(DateTime\Duration::hours(3)); $tomorrow = $now->plusDays(1); $nextMonth = $now->plusMonths(1); $lastYear = $now->minusYears(1); // Timestamps for precise timing $start = DateTime\Timestamp::now(); // ... do work ... $end = DateTime\Timestamp::now(); $elapsed = $end->since($start); // Returns Duration IO\write_line('Elapsed: %f seconds', $elapsed->getTotalSeconds()); // Monotonic clock (unaffected by system time changes) $mono = DateTime\Timestamp::monotonic(); // Formatting IO\write_line('RFC3339: %s', $now->toRfc3339()); IO\write_line('ISO 8601: %s', $duration->toIso8601()); // PT2H30M15S // Parsing $parsed = DateTime\Duration::fromIso8601('PT1H45M'); // Comparison $now->isAfter($earlier); // bool $now->isBefore($later); // bool $now->equals($other); // bool ``` ## Channel Communication The `Channel` component provides Go-style channels for communication between concurrent tasks with bounded and unbounded variants. ```php use Psl\Channel; use Psl\Async; // Bounded channel (max capacity) [$receiver, $sender] = Channel\bounded(10); // Unbounded channel (no limit) [$receiver, $sender] = Channel\unbounded(); Async\main(static function() use ($receiver, $sender): int { // Producer Async\run(static function() use ($sender): void { $sender->send('message 1'); $sender->send('message 2'); $sender->close(); })->ignore(); // Consumer while (true) { try { $message = $receiver->receive(); echo "Got: $message\n"; } catch (Channel\Exception\ClosedChannelException) { break; } } // Non-blocking operations $sent = $sender->trySend('maybe'); // Returns bool $message = $receiver->tryReceive(); // Returns ?T // Check state $sender->isClosed(); $receiver->isEmpty(); $receiver->isFull(); $receiver->count(); return 0; }); ``` ## Collections The `Collection` component provides typed, object-oriented collection classes including Vector, Map, and Set with both immutable and mutable variants. ```php use Psl\Collection\Vector; use Psl\Collection\MutableVector; use Psl\Collection\Map; use Psl\Collection\Set; use Psl\Str; // Immutable Vector $names = Vector::fromArray(['Alice', 'Bob', 'Charlie']); $names->count(); // 3 $names->at(0); // 'Alice' $names->first(); // 'Alice' $names->last(); // 'Charlie' $names->toArray(); // ['Alice', 'Bob', 'Charlie'] // Filtering and mapping return new immutable vectors $short = $names->filter(fn(string $n): bool => Str\length($n) <= 3); $upper = $names->map(Str\uppercase(...)); // Mutable Vector $tasks = MutableVector::fromArray(['eat', 'sleep']); $tasks->add('code'); $tasks->remove(0); // removes 'eat', re-indexes $tasks->toArray(); // ['sleep', 'code'] // Map (key-value pairs) $scores = Map::fromArray(['alice' => 100, 'bob' => 85]); $scores->at('alice'); // 100 $scores->contains('bob'); // true // Set (unique values) $tags = Set::fromArray(['php', 'async', 'php']); // Deduped $tags->contains('php'); // true $tags->count(); // 2 ``` ## Data Structures The `DataStructure` component provides Queue, Stack, and PriorityQueue implementations. ```php use Psl\DataStructure; // Queue (FIFO) $queue = new DataStructure\Queue(); $queue->enqueue('first'); $queue->enqueue('second'); $queue->enqueue('third'); $queue->count(); // 3 $queue->peek(); // 'first' (doesn't remove) $queue->pull(); // 'first' (removes, returns null if empty) $queue->dequeue(); // 'second' (removes, throws if empty) // Stack (LIFO) $stack = new DataStructure\Stack(); $stack->push('bottom'); $stack->push('middle'); $stack->push('top'); $stack->peek(); // 'top' $stack->pull(); // 'top' $stack->pop(); // 'middle' // Priority Queue $pq = new DataStructure\PriorityQueue(); $pq->enqueue('low', 1); $pq->enqueue('high', 10); $pq->enqueue('medium', 5); $pq->dequeue(); // 'high' (highest priority first) $pq->dequeue(); // 'medium' ``` ## Regex Operations The `Regex` component provides type-safe regular expression matching with proper exception handling. ```php use Psl\Regex; // Check if pattern matches Regex\matches('hello@example.com', '/^[^@]+@[^@]+$/'); // true Regex\matches('not-an-email', '/^[^@]+@[^@]+$/'); // false Regex\matches('foo bar foo', '/foo/', offset: 4); // true // First match with captures $match = Regex\first_match('Hello World', '/(\w+) (\w+)/'); // ['Hello World', 'Hello', 'World'] // All matches $matches = Regex\every_match('a1 b2 c3', '/([a-z])(\d)/'); // [['a1', 'a', '1'], ['b2', 'b', '2'], ['c3', 'c', '3']] // Replace $result = Regex\replace('hello world', '/world/', 'PHP'); // 'hello PHP' // Replace with callback $result = Regex\replace_with('a1 b2', '/([a-z])(\d)/', fn($m) => $m[1] . ($m[2] + 1)); // 'a2 b3' // Split $parts = Regex\split('a,b;c', '/[,;]/'); // ['a', 'b', 'c'] // Typed captures (with Type system) $match = Regex\capture_groups( 'user:123', '/(?\w+):(?\d+)/', Type\shape(['name' => Type\string(), 'id' => Type\int()]) ); // ['name' => 'user', 'id' => 123] ``` ## Encoding The `Encoding` component provides Base64 and Hex encoding/decoding. ```php use Psl\Encoding\Base64; use Psl\Encoding\Hex; // Base64 $encoded = Base64\encode('Hello, World!'); // 'SGVsbG8sIFdvcmxkIQ==' $decoded = Base64\decode($encoded); // 'Hello, World!' // URL-safe Base64 variant $urlSafe = Base64\encode('Hello, World!', Base64\Variant::UrlSafe); // Hex $hex = Hex\encode('Hello'); // '48656c6c6f' $decoded = Hex\decode($hex); // 'Hello' ``` ## Math Operations The `Math` component provides mathematical functions with proper typing and exception handling. ```php use Psl\Math; // Basic operations Math\abs(-5); // 5 Math\ceil(4.2); // 5.0 Math\floor(4.8); // 4.0 Math\round(3.456, 2); // 3.46 Math\sqrt(16.0); // 4.0 Math\div(7, 2); // 3 (integer division, throws on zero) // Min/max Math\min([3, 1, 4]); // 1 Math\max([3, 1, 4]); // 4 Math\minmax([3, 1, 4]); // [1, 4] // Clamping Math\clamp(5, 0, 10); // 5 Math\clamp(-5, 0, 10); // 0 Math\clamp(15, 0, 10); // 10 // Statistics Math\mean([1, 2, 3, 4, 5]); // 3.0 Math\median([1, 2, 3, 4, 5]); // 3.0 Math\sum([1, 2, 3, 4, 5]); // 15 // Trigonometry Math\sin(Math\PI / 2); // 1.0 Math\cos(0); // 1.0 Math\tan(Math\PI / 4); // ~1.0 // Base conversion Math\to_base(255, 16); // 'ff' Math\from_base('ff', 16); // 255 Math\base_convert('ff', 16, 2); // '11111111' ``` PSL serves as a comprehensive foundation for building type-safe, async-capable PHP applications. Its main use cases include: building concurrent network services with the TCP/UDP/Unix socket APIs; validating and transforming untrusted input through the Type system; managing files and processes safely with proper error handling; implementing cryptographic operations without security footguns; and replacing PHP's inconsistent built-in functions with predictable, well-typed alternatives. The library integrates seamlessly with existing PHP frameworks through its PSR-compatible interfaces and RevoltPHP-based async foundation. Applications can adopt PSL incrementally, starting with specific components like Type validation or Vec/Dict operations, then expanding to async networking or cryptography as needed. The consistent API design across all components means learning one part of PSL makes the rest immediately familiar.