Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Psl Laravel Package

azjezz/psl

PSL (PHP Standard Library) offers a consistent, well-typed set of safer, async-ready APIs to replace PHP primitives. Covers async, collections, networking, I/O, cryptography, terminal UI, and type-safe data validation with predictable errors.

View on GitHub
Deep Wiki
Context7
6.2.1

Security Release

This release fixes a server-side HTTP/2 vulnerability in the Psl\H2 component (GHSA-pw9p-jvrm-f7rm).

Impact

Psl\H2\ServerConnection did not validate that the total bytes received in HTTP/2 DATA frames matched the content-length header declared in the initial HEADERS frame, in violation of RFC 9113 §8.1.1 and §8.1.2.6. #777

A malicious client could:

  • Send more DATA bytes than declared, smuggling additional content past application-level size limits.
  • Send fewer DATA bytes than declared and close the stream early, causing applications that trust the declared length to behave incorrectly.

This affects consumers using Psl\H2\ServerConnection directly to accept untrusted client traffic. Consumers of documented high-level PSL APIs are not affected.

Patches

  • Parses and validates content-length on server-side HEADERS receive (RFC 9110 §8.6: must be a non-negative decimal integer).
  • Tracks cumulative DATA frame payload length per stream.
  • Throws Psl\H2\Exception\StreamException on mismatch or overflow.

Client-side validation is intentionally not performed, as RFC 9110 §9.3.2 permits HEAD responses to declare content-length without sending DATA.

Additional fixes

  • Psl\H2\ConnectionTrait::waitForSendWindow() now flushes pending buffered writes before suspending. Without this, frames written inside a buffered() block never reach the wire, and a peer that only sends WINDOW_UPDATE after seeing our DATA would deadlock.

Upgrade

composer require php-standard-library/psl:^6.2.1

Credit

Discovered during internal review prior to public exploitation.

6.1.2

Security Release

This release fixes a server-side HTTP/2 vulnerability in the Psl\H2 component (GHSA-pw9p-jvrm-f7rm).

Impact

Psl\H2\ServerConnection did not validate that the total bytes received in HTTP/2 DATA frames matched the content-length header declared in the initial HEADERS frame, in violation of RFC 9113 §8.1.1 and §8.1.2.6. #778

A malicious client could:

  • Send more DATA bytes than declared, smuggling additional content past application-level size limits.
  • Send fewer DATA bytes than declared and close the stream early, causing applications that trust the declared length to behave incorrectly.

This affects consumers using Psl\H2\ServerConnection directly to accept untrusted client traffic. Consumers of documented high-level PSL APIs are not affected.

Patches

  • Parses and validates content-length on server-side HEADERS receive (RFC 9110 §8.6: must be a non-negative decimal integer).
  • Tracks cumulative DATA frame payload length per stream.
  • Throws Psl\H2\Exception\StreamException on mismatch or overflow.

Client-side validation is intentionally not performed, as RFC 9110 §9.3.2 permits HEAD responses to declare content-length without sending DATA.

Additional fixes

  • Psl\H2\ConnectionTrait::waitForSendWindow() now flushes pending buffered writes before suspending. Without this, frames written inside a buffered() block never reach the wire, and a peer that only sends WINDOW_UPDATE after seeing our DATA would deadlock.

Upgrade

composer require php-standard-library/psl:^6.1.2

Credit

Discovered during internal review prior to public exploitation.

6.2.0

PSL 6.2.0

A massive release — three new networking stack components (HTTP, SMTP, DNS), the EitherOrBoth type with full-outer-join iterators, a major IO toolkit expansion, and broad covariance improvements across the type system.

New Components

HTTP Stack

  • HTTP\Message — version-agnostic HTTP message abstractions. Request/Response value objects with streaming bodies (ReadHandleInterface), FieldMap (ordered, case-insensitive headers with lazy index), ProtocolVersion covering HTTP/1.0 through HTTP/3, trailers as Async\Awaitable<FieldMap>, status/method constants per RFC 9110, and Transaction/Exchange for informational (1xx) responses and HTTP/2 server-push pairs.
  • HTTP\Client — async HTTP/1.1 and HTTP/2 client with automatic protocol negotiation via ALPN. Connection pooling (H1 idle reuse, H2 session sharing across concurrent requests), event-driven stream dispatch, transparent reconnection on GOAWAY/TCP reset, RedirectClient and RetryClient decorators, per-request SendConfiguration, SSRF protection via DeniedDestinationsMiddleware, SOCKS5 proxy and HTTP CONNECT tunnel support, H2 flow control with BDP auto-tuning, and 104 integration tests against httpbun.

Mail Stack

  • MIME — comprehensive RFC 2045–2049 toolkit. Media type parsing and content negotiation, MIME part construction with automatic transfer encoding, streaming multipart bodies and parsing (alternative, related, form, generic), Content-Disposition with safe filename extraction, RFC 2231 parameter encoding with continuations and charset conversion, content sniffing from bytes or seekable handles, S/MIME signing/verification/encryption/decryption per RFC 5652/8551, and DKIM signing with RSA-SHA256 and Ed25519-SHA256 per RFC 6376/8463.
  • Message — RFC 5322 internet message construction, parsing, and serialization. Typed header fields with fluent with*() mutation, address methods accepting string|Mailbox|AddressList, streaming serialize()/parse(), reply/reply-all/forward with automatic threading headers, RFC 5321 SMTP envelope derivation, and full RFC 5322 address parsing including RFC 2047 encoded-word support.
  • SMTP — RFC 5321 SMTP client with connection pooling. Low-level Connection for protocol-level operations and high-level Transport managing the full lifecycle (EHLO/HELO, STARTTLS, AUTH, send, RSET). Implicit TLS on port 465 and STARTTLS upgrade with automatic detection, SMTP pipelining (RFC 2920), BDAT chunking (RFC 3030), DSN (RFC 3461), REQUIRETLS (RFC 8689), MT-PRIORITY (RFC 6710), DELIVERBY (RFC 2852), FUTURERELEASE (RFC 4865), BINARYMIME/8BITMIME/SMTPUTF8 negotiation, IDN punycode for international addresses, partial recipient success tracking, CRLF/null byte injection protection, and five authentication mechanisms: PLAIN, LOGIN, XOAUTH2, CRAM-MD5, SCRAM-SHA-256.

DNS Stack

  • DNS — async DNS resolution with full protocol support. SystemResolver mirrors OS DNS behavior; UDP and pooled TCP resolvers with automatic TCP fallback on truncation; DNS-over-TLS (DoT) and DNS-over-HTTPS (DoH, RFC 8484). RacingResolver races multiple nameservers concurrently, SplitHorizonResolver routes by domain, SearchDomainResolver expands short names, HostsFileResolver checks the OS hosts file, CachedResolver decorator with TTL-aware caching, and StaticResolver for tests. Cross-platform system configuration loading on Linux, macOS, and Windows. EDNS0 extensions (cookies, client subnet, padding, NSID, keepalive). 20+ record types covering A, AAAA, NS, CNAME, MX, TXT, SRV, SOA, PTR, CAA, SSHFP, TLSA, SVCB, HTTPS, LOC, NAPTR, DS, DNSKEY, RRSIG, NSEC, NSEC3.
  • DNSSEC — full DNSSEC validation chain. SecureResolver validates RRSIG signatures, TrustChainResolver walks DS/DNSKEY from root to target zone, CachedTrustChainResolver for performance, StaticTrustChainResolver for offline use. NSEC and NSEC3 authenticated denial of existence proofs. Seven signature algorithms: RSA/SHA-1, RSA/SHA-256, RSA/SHA-512, ECDSA P-256, ECDSA P-384, Ed25519, Ed448. Specific exceptions for signature failures, broken trust chains, invalid proofs, and unsigned responses.

EitherOrBoth + Full-Outer-Join Iterators

  • EitherOrBoth — three-variant disjoint union (Left/Right/Both) for values that may be present on either or both of two sides. Inspired by Rust's itertools::EitherOrBoth and Haskell's Data.These. Unlike Either, no side is privileged. Use cases: three-way diffs (insert/delete/update events), layered config merging, multi-source enrichment, dual-validation with independent failure paths, snapshot comparison, request/response pairing. Full surface: map, mapLeft, mapRight, mapAny, swap, proceed, apply, containsLeft, containsRight, plus left()/right()/both() free constructors.
  • Iter\merge_join_by / Iter\merge_join_by_key — full-outer-join stream producers yielding EitherOrBoth events. merge_join_by is a lazy two-cursor merge over sorted inputs (O(1) memory, Comparison\Order-returning comparator). merge_join_by_key is a hash-based variant for keyed inputs that need no pre-sorting (O(|right|) memory).

IO Toolkit Expansion

Eight new handle types for streaming composition:

  • IterableReadHandle — lazily consume an iterable<string> without buffering.
  • ConcatReadHandle — read from two handles in sequence, switching at EOF.
  • JoinedReadWriteHandle — combine separate read and write handles into one.
  • TeeWriteHandle — fan out writes to two handles with backpressure buffering.
  • SinkWriteHandle / SinkReadHandle / SinkReadWriteHandle/dev/null-like handles for discarding writes and reporting EOF immediately on reads.
  • TruncatedReadHandle — silently report EOF after N bytes.
  • BoundedReadHandle — throw RuntimeException if the underlying handle exceeds N bytes.
  • FixedLengthReadHandle — read exactly N bytes, throw on premature EOF.

Plus IO\copy_chunked() and IO\copy_bidirectional_chunked() for explicit chunk-size control.

Type System: Covariance

Read-only template parameters across the library are now annotated [@template-covariant](https://github.com/template-covariant), letting values flow into wider declarations:

  • Async\Awaitable<T>, Promise\PromiseInterface<T>
  • Result\ResultInterface<T>, Result\Success<T>, Result\Failure<T, Te>
  • Option\Option<T>
  • Either\Either<TLeft, TRight>, Either\Left<TLeft>, Either\Right<TRight>
  • Tree\NodeInterface<T>, Tree\LeafNode<T>, Tree\TreeNode<T>
  • Immutable Collection interfaces and implementations (Map, Set, Vector)

Async\Sequence, KeyedSequence, Semaphore, and KeyedSemaphore now correctly distinguish contravariant inputs from covariant outputs.

HTTP/2 (H2)

  • New unified Configuration replacing the deprecated ClientConfiguration and ServerConfiguration. Both ClientConnection and ServerConnection accept it. Client-side BDP auto-tuning is now available when maxReceiveWindowSize is set on the unified config.

TCP & Type Additions

  • TCP\bindTo — bind to a specific local address before connecting or listening. Available on both ConnectConfiguration and ListenConfiguration with withBindTo() builders; connect() respects it via socket.bindto.
  • Type\bool() — now coerces 'true'/'false' string literals (thanks @veewee, #735).
  • Type\class_string — allow null argument to assert or coerce a bare class-string.
  • HTTP\Client\SendConfiguration::$connectionTimeout — per-request maximum duration for TCP + TLS handshake, using a linked cancellation token.

Fixes

  • IO\copy() flushes the writer if it implements BufferedWriteHandleInterface — no data left in buffers.
  • Async\State no longer captures $this in queued callbacks, fixing delayed GC of Deferred/Awaitable chains.
  • URI correctly parses bare IPv6 addresses (e.g., http://::1/path) as IPHost instead of misparsing as a registered name with numeric port.
  • H2 separates maxConcurrent (peer's limit on our streams) from peerMaxConcurrent (our limit on peer's streams), so client's own SETTINGS no longer limit its outgoing streams.
  • H2\BDPEstimator emits an initial connection-level WINDOW_UPDATE during initialize(), bringing the receive window from the RFC default (65535) up to initialWindowSize to prevent flow-control stalls under burst concurrency.
  • H2 waiter notification copies the list before iterating and properly removes satisfied waiters — no iteration corruption or memory leaks.
  • IO\ResourceHandle read/write callbacks and cancellation subscriptions null out the suspension reference before resuming or throwing — no more "Must call suspend() before calling throw()" errors during handle destruction or shutdown races.
  • RFC 2047 encoded-word encoder no longer embeds CRLF line folding in the output; folding is now the header serializer's responsibility, fixing header/body separation in serialized messages.

Deprecations

Will be removed in PSL 7.0:

  • TCP\Socket — use ConnectConfiguration::$bindTo / ListenConfiguration::$bindTo.
  • H2\ClientConfiguration and H2\ServerConfiguration — use the unified H2\Configuration.

CI

  • Added httpbun, microsocks, and tinyproxy services to unit-tests, code-coverage, mutation-tests, and package-tests workflows for HTTP client integration testing.

Install: composer require php-standard-library/psl:^6.2

6.1.1

PSL 6.1.1

Str\chr() and Str\from_code_points() now reject invalid Unicode code points

Str\chr() previously returned an empty string for invalid code points (negative values, surrogates, values above U+10FFFF) because mb_chr() returns false and it was silently cast to string. It now throws Str\Exception\OutOfBoundsException.

Str\from_code_points() had a hand-rolled UTF-8 encoder that silently produced invalid byte sequences; encoding surrogates, wrapping out-of-range values via modulo, and accepting negative inputs. The implementation has been replaced with a simple loop over Str\chr(), making both functions fully consistent. Invalid code points now throw Str\Exception\OutOfBoundsException.

use Psl\Str;

// These all threw no error before, now they throw OutOfBoundsException:
Str\chr(-1);
Str\chr(0xD800);        // surrogate
Str\chr(0x110000);      // above Unicode max

Str\from_code_points(72, 0xD800, 111);  // throws on the surrogate

Valid inputs are unaffected — chr() and from_code_points() produce identical output for all valid Unicode code points (U+0000..U+D7FF, U+E000..U+10FFFF).

Explicit function resolution across the codebase

All ambiguous function calls have been made explicit. Every call site now uses either a use function import for global PHP functions or namespace\foo() for same-namespace functions.

Documentation

  • Str\width(), Str\truncate(), and Str\width_slice() PHPDoc now explicitly states that width is defined by mb_strwidth() / mb_strimwidth(), and cross-references related functions like Str\length(), Str\Grapheme\length(), and Str\Grapheme\slice().

Testing

  • The H2 rate limiter window-reset test is now skipped on Windows, where usleep() resolution is too coarse for sub-millisecond timing assertions.
6.1.0

PSL 6.1.0

In PSL 5.x, we focused on the foundational networking stack-TCP, TLS, Unix sockets, UDP, and connection pooling. It was all about getting the low-level plumbing right.

With the 6.x series, we're moving up the stack and diving into protocols. Our ultimate goal is to bring robust support for HTTP/2, DNS, SMTP, WebSockets, and more. PSL 6.1.0 is the crucial first step: it delivers the core infrastructure that all of these upcoming features will rely on.

What's Coming Next?

Everything in 6.1 was built with a clear destination in mind. We are paving the way for:

  • 🌐 HTTP Client - Powered by our new H2 and TLS implementations, featuring automatic protocol negotiation, HTTP/1.1 fallback, and connection pooling.
  • 🖥️ HTTP Server – A fully asynchronous HTTP/1.1 and HTTP/2 server with middleware support.
  • 🔍 DNS – A complete async resolver supporting DNSSEC, DNS-over-TLS, caching, and racing resolvers.
  • 📧 SMTP – Fully asynchronous email delivery.
  • 🔌 WebSockets – Supported both standalone over HTTP/1.1 and via H2's extended CONNECT.

The components introduced today are the engine for this roadmap. The new H2 connections will drive the HTTP client and server, the new async Cache will back the DNS resolver, and the new Compression system will handle content-encoding seamlessly.


What's New in 6.1.0

🗜️ Streaming Compression

We've added streaming compression and decompression natively to IO handles. By defining your own CompressorInterface or DecompressorInterface (brotli, gzip, zstd, etc.), PSL gives you four handle decorators to wire them directly into the IO system:

  • CompressingReadHandle & CompressingWriteHandle
  • DecompressingReadHandle & DecompressingWriteHandle

We've also included compress() and decompress() convenience functions for simple, one-shot operations. Under the hood, write handles implement the new BufferedWriteHandleInterface for explicit flushing and cancellation, while read handles accept configurable chunk sizes. Compressors automatically reset after calling finish(), making them easily reusable across streams.

📦 HPACK (HTTP/2 Header Compression)

This release includes a complete RFC 7541 encoder and decoder, featuring static table lookups, dynamic table indexing, and Huffman coding.

We wanted to be absolutely certain of its reliability, so we tested it against 14 independent implementations from the http2jp test suite. That translates to 1,172 tests and over 102,000 assertions, covering every encoding variant and edge case with full roundtrip verification.

H2 (HTTP/2 Binary Framing)

We’ve shipped full support for the HTTP/2 binary framing protocol (RFC 9113), plus key extensions.

To keep responsibilities clean, connections are split by role. ServerConnection handles client prefaces, response headers, server pushes, Alt-Svc, and ORIGIN. Meanwhile, ClientConnection manages connection prefaces, priority signaling, and extended CONNECT.

Comprehensive Frame Support:

  • All 10 core frame types.
  • ALTSVC (RFC 7838) for HTTP/3 migration signaling.
  • ORIGIN (RFC 8336) for connection coalescing.
  • PRIORITY_UPDATE (RFC 9218) for extensible prioritization.

Smart, Async-Native Flow Control: We've designed flow control to get out of your way. sendAllData() automatically chunks payloads by window size and waits for updates. waitForSendWindow() suspends the fiber entirely (zero polling!) and resumes exactly when the window opens. Multiple fibers can wait on different streams with independent cancellation, and connection-level updates efficiently wake all relevant waiters.

Additional H2 Features:

  • BDP auto-tuning for dynamic receive window sizing.
  • Built-in rate limiting to prevent SETTINGS, PING, or RST_STREAM floods.
  • Auto-GOAWAY on protocol errors, eliminating manual error handling.
  • Deep stream introspection (getStreamState(), activeStreamCount(), isConnected()).
  • Extended CONNECT (RFC 8441) to bootstrap WebSockets over H2.
  • Immutable ServerConfiguration and ClientConfiguration using fluent with* builders.

🧠 Async-Safe Memory Cache

We're introducing an async-safe, in-memory LRU cache. The standout feature here is per-key atomicity powered by KeyedSequence.

If two fibers request the same cache key simultaneously, only one will compute the result. The other simply waits and receives the cached value—preventing cache stampedes and eliminating duplicate work.

  • LocalStore: A bounded LRU cache with a configurable max size and TTL support. It uses an event loop timer for proactive expiration, dropping to zero overhead when there are no expiring entries.
  • NullStore: A dummy cache that never stores and always recomputes. It's perfect for testing or temporarily disabling caching without having to modify your calling code.

🔌 IO Enhancements

We've introduced BufferedWriteHandleInterface, which extends the standard WriteHandleInterface with a flush() method. This is essential for handles that buffer data internally (like the new compression writers) and need an explicit "send everything now" trigger with full cancellation support.

6.0.3

PSL 6.0.3

No code changes. This release improves the release infrastructure.

What changed

  • Annotated tags: Split repository tags are now created as annotated tags via the GitHub API, removing the "unverified" warning shown on 6.0.0-6.0.2 tags.
  • Immutable tags: All 62 repositories now have tag immutability rulesets. Tags cannot be deleted, updated, or force-pushed.
  • Maintenance branch sync: The splitter now syncs the maintenance branch (e.g. 6.0.x) to the tag before splitting, ensuring split repos always receive the correct commits for patch releases.

Full changelog

See CHANGELOG.md for details.

6.0.2

PSL 6.0.2

Patch release fixing a bug in IO\Reader that affected non-blocking stream reads (TLS, TCP, etc.).

Bug fixes

IO: Reader no longer treats empty non-blocking reads as EOF

Reader::readUntil() and Reader::readUntilBounded() assumed that an empty read() meant end-of-stream. On non-blocking handles (TLS, TCP, Unix sockets), read() can return empty before data arrives. This caused readLine() to return the entire stream content as a single string instead of splitting into individual lines.

This bug affected any code using IO\Reader with network streams. If you were using readLine(), readUntil(), or readUntilBounded() on a non-blocking stream and getting unexpected results, this is the fix.

Docs: source links point to correct paths

Documentation source links (See src/Psl/Default/ for the full API) now link to packages/default/src/Psl/Default/ instead of the non-existent top-level src/Psl/Default/.

Full changelog

See CHANGELOG.md for details.

6.0.0

PSL 6.0.0

PSL 6.0 is the biggest release in the project's history. New home, new packages, new capabilities.

A new home

PSL has moved. The repository, the organization, the website - everything has a new address:

The azjezz/psl package is now abandoned. Run composer require php-standard-library/php-standard-library to switch.

The namespace has not changed. It is Psl\, and it will always remain Psl\.

61 standalone packages

PSL is now split into 61 independently installable packages. You no longer need to pull in the entire library.

Need just type-safe coercion? composer require php-standard-library/type

Building an async TCP server? composer require php-standard-library/tcp

Working with URIs? composer require php-standard-library/uri

Every package declares its own dependencies, so you only get what you actually use. The full library install still works for those who want everything:

composer require php-standard-library/php-standard-library

All 61 packages live under the php-standard-library GitHub organization, each with its own read-only split repository for Composer.

New components

URI, IRI, URL

Full RFC-compliant resource identifier handling:

  • URI - RFC 3986 parsing, normalization, reference resolution, and RFC 6570 URI Template expansion (Levels 1-4)
  • IRI - RFC 3987 Internationalized Resource Identifiers with Unicode support, Punycode, and IDNA 2008
  • URL - Strict URL type with scheme/authority validation and default port stripping

Punycode

Standalone RFC 3492 Punycode encoding and decoding for internationalized domain names.

Cancellation tokens

A new cancellation system replaces the old Duration $timeout pattern across all async/IO operations:

  • CancellationTokenInterface - base contract
  • TimeoutCancellationToken - auto-cancels after a duration
  • SignalCancellationToken - manually triggered cancellation
  • LinkedCancellationToken - cancelled when either of two inner tokens fires

More highlights

  • TaskGroup and WaitGroup for structured concurrency
  • QuotedPrintable and EncodedWord encoding (RFC 2045, RFC 2047)
  • Streaming Base64/Hex/QuotedPrintable IO handles
  • TLS\Listener for wrapping any listener with TLS
  • TCP\RestrictedListener for IP/CIDR-based access control
  • Network\CompositeListener for accepting from multiple listeners
  • BufferedReadHandleInterface with readByte(), readLine(), readUntil()
  • Configuration objects for TCP, Unix, UDP, and Socks

Breaking changes

This is a major release with breaking changes. The most impactful:

Cancellation replaces timeouts. All null|Duration $timeout parameters are now CancellationTokenInterface $cancellation = new NullCancellationToken().

// Before (5.x)
$data = $reader->read(timeout: Duration::seconds(5));

// After (6.0)
$data = $reader->read(cancellation: new Async\TimeoutCancellationToken(Duration::seconds(5)));

Naming conventions. All variables, parameters, and properties now use $camelCase.

Configuration objects. TCP\listen(), TCP\connect(), Unix\listen(), UDP\Socket::bind(), and Socks\Connector now accept configuration objects instead of individual parameters.

Removed timeout exceptions. IO\Exception\TimeoutException, Network\Exception\TimeoutException, Process\Exception\TimeoutException, and Shell\Exception\TimeoutException are removed. Use Async\Exception\CancelledException instead.

TLS renamed. TLS\ServerConfig -> TLS\ServerConfiguration, TLS\ClientConfig -> TLS\ClientConfiguration.

See the full CHANGELOG for the complete list.

Bug fixes

  • RetryConnector backoff sleep now respects cancellation tokens
  • IO\write(), IO\write_line(), IO\write_error(), IO\write_error_line(), and Str\format() no longer crash when the message contains % characters and no arguments are passed

Thank you

PSL is built by its community. Thank you to everyone who contributed code, reported bugs, sponsored the project, or simply used it in production.

5.5.0

PSL 5.5.0

IO: Bounded Reads

Reader::readUntilBounded() reads from a handle until a suffix is found, just like readUntil(), but enforces a maximum byte limit. If the suffix is not encountered within $max_bytes, an IO\Exception\OverflowException is thrown.

This is essential when reading from untrusted sources. for example, capping HTTP header lines so a malicious client cannot exhaust memory by sending an endless line:

use Psl\IO;

$reader = new IO\Reader($connection);

// Read a header line, but never buffer more than 8KB
$line = $reader->readUntilBounded("\r\n", max_bytes: 8192);

Type: Type\json_decoded() and Type\nullish()

Two new type coercions from [@veewee](https://github.com/veewee):

  • Type\json_decoded(TypeInterface $inner): accepts a JSON string and transparently decodes it, then coerces the result through $inner. Useful for APIs and form fields that pass structured data as JSON strings.

  • Type\nullish(TypeInterface $inner): matches null, the absence of a key (for shape fields), and the inner type. Ideal for optional-and-nullable shape fields where "missing" and "null" should be treated the same.


Documentation: psl.carthage.software/ | IO | Type


Full Changelog: https://github.com/azjezz/psl/compare/5.4.0...5.5.0

5.4.0

PSL 5.4.0

TCP: Backlog Configuration and Batch Accept

TCP\listen() now accepts a backlog parameter (default 512) to configure the OS-level queue of pending connections. The listener also now drains the accept backlog in a loop instead of accepting one connection per event-loop tick, dramatically improving throughput under high connection rates.

use Psl\TCP;

$listener = TCP\listen('127.0.0.1', 8080, backlog: 4096);

New: Dict\{filter_nonnull_by, map_nonnull}, Vec\{filter_nonnull_by, map_nonnull}

New collection helpers for filtering and mapping with null-awareness.


Documentation: psl.carthage.software/ | TCP


New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/5.3.0...5.4.0

5.3.0

PSL 5.3.0

New: IO\spool()

Create a handle that writes to memory until a threshold is reached, then transparently spills to a temporary file on disk. Useful for buffering data of unknown size without risking excessive memory usage.

use Psl\IO;

$handle = IO\spool(); // default 2MB threshold
$handle->writeAll($data);
$handle->seek(0);
$contents = $handle->readAll();
$handle->close();

// Custom threshold: spool to disk after 64 bytes
$small = IO\spool(maxMemory: 64);

The returned handle implements CloseHandleInterface, SeekHandleInterface, ReadHandleInterface, WriteHandleInterface, and StreamHandleInterface.


Documentation: psl.carthage.software/5.3.0/ | IO


Full Changelog: https://github.com/azjezz/psl/compare/5.2.0...5.3.0

5.2.0

PSL 5.2.0

New: IP Component

Immutable, binary-backed value object for IPv4 and IPv6 addresses. Parse, classify, compare, and format IP addresses with a clean API.

use Psl\IP\Address;

$addr = Address::parse('192.168.1.1');
$addr->family;            // Family::V4
$addr->isPrivate();       // true
$addr->isGlobalUnicast(); // false
$addr->toArpaName();      // '1.1.168.192.in-addr.arpa'

$v6 = Address::v6('2001:db8::1');
$v6->toString();         // '2001:db8::1'
$v6->toExpandedString(); // '2001:0db8:0000:0000:0000:0000:0000:0001'

Improved: CIDR\Block::contains()

Block::contains() now accepts string|IP\Address:

use Psl\CIDR\Block;
use Psl\IP\Address;

$block = new Block('192.168.1.0/24');
$block->contains(Address::v4('192.168.1.100')); // true

Documentation: psl.carthage.software/5.2.0/ | IP | CIDR


Full Changelog: https://github.com/azjezz/psl/compare/5.1.0...5.2.0

5.1.0

PSL - Crown 5.1.0

Features

  • TLS connection pooling: New TLS\TCPConnector implements TCP\ConnectorInterface, enabling TLS connections to be pooled via TCP\SocketPool. Pass a TCPConnector to SocketPool and get automatic connection reuse without repeated TLS handshakes.
  • TLS\StreamInterface now extends TCP\StreamInterface, making TLS streams compatible with any API that accepts TCP streams.

Example

$pool = new TCP\SocketPool(
  new TLS\TCPConnector(
    new TCP\Connector(),
    new TLS\Connector($config),
  ),
);

$stream = $pool->checkout('example.com', 443);
// ... use stream ...
$pool->checkin($stream);

// Next checkout reuses the TLS connection
$stream = $pool->checkout('example.com', 443);

Full Changelog: https://github.com/azjezz/psl/compare/5.0.0...5.1.0

5.0.0

PSL - Crown 5.0

PSL 5.0 - nicknamed Crown - is the biggest release of the PHP Standard Library to date, introducing 10 new components, a complete networking stack rewrite, and significant performance improvements across the board.

Requires PHP 8.4+.

Crypto

Full-featured cryptography built on libsodium: symmetric and asymmetric encryption, digital signatures, AEAD, key derivation (KDF, HKDF), key exchange, and stream ciphers, all with a type-safe, hard-to-misuse API.

use Psl\Crypto\Symmetric;

$key = Symmetric\generate_key();
$ciphertext = Symmetric\seal('Hello, World!', $key);
$plaintext = Symmetric\open($ciphertext, $key);
// 'Hello, World!'
use Psl\Crypto\Signing;

$keyPair = Signing\generate_key_pair();
$signature = Signing\sign('This message is authentic.', $keyPair->secretKey);
$valid = Signing\verify($signature, 'This message is authentic.', $keyPair->publicKey);
// true

Binary

Structured binary data parsing and encoding with a fluent Reader/Writer API. Read and write integers, floats, and strings in any byte order. Ideal for building protocol parsers and working with binary formats.

use Psl\Binary\{Reader, Writer, Endianness};

$data = new Writer(endianness: Endianness::Big)
    ->u8(1)           // version
    ->u16(0x0042)     // type
    ->u32(5)          // payload length
    ->bytes('Hello')  // payload
    ->toString();

$reader = new Reader($data, Endianness::Big);
$version = $reader->u8();      // 1
$type    = $reader->u16();     // 0x0042
$length  = $reader->u32();     // 5
$payload = $reader->bytes($length); // 'Hello'

Networking Stack Rewrite

The Network, TCP, TLS, UDP, Unix, CIDR, and Socks components were rewritten from scratch with connection pooling, retry logic, socket pairs, and first-class TLS support.

use Psl\TCP;

$listener = TCP\listen('127.0.0.1');
$connection = $listener->accept();
$data = $connection->readAll();
$connection->writeAll($data);
use Psl\TLS;

$tls = TLS\connect('example.com', 443);
$tls->writeAll("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
$tls->shutdown();
$response = $tls->readAll();
use Psl\CIDR;

$block = new CIDR\Block('192.168.1.0/24');
$block->contains('192.168.1.100'); // true
$block->contains('192.168.2.1');   // false

Process

Async process management with non-blocking I/O, inspired by Rust's Command API. A safer, higher-level replacement for proc_open and friends. Psl\Shell\execute is now powered by it under the hood.

use Psl\Process\Command;

$output = Command::create('echo')
    ->withArguments(['Hello', 'from', 'process'])
    ->output();

if ($output->status->isSuccessful()) {
    $output->stdout; // 'Hello from process'
}

Terminal & Ansi

A full terminal UI framework: buffered rendering, layouts, widgets, keyboard/mouse event handling, and ANSI styling. Build rich interactive TUI applications entirely in PHP.

use Psl\Async;
use Psl\Terminal;
use Psl\Terminal\{Event, Widget};

Async\main(static function (): int {
    $app = Terminal\Application::create(new MyState(), title: 'My App');

    $app->on(Event\Key::class, static function (Event\Key $event) use ($app): void {
        if ($event->is('ctrl+c')) {
            $app->stop();
        }
    });

    return $app->run(static function (Terminal\Frame $frame, MyState $state): void {
        Widget\Paragraph::new([
            Widget\Line::new([Widget\Span::raw('Hello, World!')]),
        ])->render($frame->rect(), $frame->buffer());
    });
});

Here's a system monitor UI demo built entirely with Psl\Terminal (source):

system-monitor

You can even build fully functional terminal games (source):

snake

DateTime Additions

New Period and Interval types for representing and manipulating durations and time spans.

use Psl\DateTime;

$period = DateTime\Period::fromParts(years: 1, months: 6, days: 15);
$period->toIso8601(); // 'P1Y6M15D'

$start = DateTime\DateTime::fromParts(DateTime\Timezone::UTC, 2024, 3, 15);
$end = DateTime\DateTime::fromParts(DateTime\Timezone::UTC, 2025, 7, 20);
$between = DateTime\Period::between($start, $end);
// 1 year(s), 4 month(s), 5 day(s)

Performance

Optimizations across Vec, Dict, Str, Iter, Type, and more components. Benchmarks show up to 100% improvement in certain functions.

Documentation

A new documentation website is available at psl.carthage.software.

Breaking Changes

  • PHP 8.4 is now the minimum required version
  • Complete networking stack rewrite (Network, TCP, Unix)
  • Psl\Env\temp_dir() now always returns a canonicalized path
  • Filesystem\create_temporary_file() now canonicalizes the temporary directory path
  • Migrated to PHPUnit 13

Bug Fixes

  • Vec\range() now uses strict comparison for float precision

Documentation: https://psl.carthage.software/


Full Changelog: https://github.com/azjezz/psl/compare/4.3.0...5.0.0

4.3.0

What's Changed

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/4.2.1...4.3.0

4.2.1

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/4.2.0...4.2.1

4.2.0

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/4.1.0...4.2.0

4.1.0

Psl Noise - 4.1.0

This release introduces two major new data structure components to the PHP Standard Library: Tree and Graph. These additions bring powerful hierarchical and relational data manipulation tools to PHP developers with PSL's signature type-safe API.

What's Changed

✨ New Features

🌳 Psl\Tree Component

A comprehensive tree data structure implementation for working with hierarchical data.

Features: Immutable tree nodes, functional operations (map, filter, reduce, fold), traversal algorithms (pre-order, post-order, level-order), search utilities, and conversion functions.

use Psl\Tree;

// Create and manipulate trees
$tree = Tree\tree('root', [
    Tree\leaf('child1'),
    Tree\tree('child2', [Tree\leaf('grandchild')]),
]);

// Functional operations
$doubled = Tree\map($tree, fn($x) => $x . '!');
$values = Tree\pre_order($tree); // ['root', 'child1', 'child2', 'grandchild']
$count = Tree\count($tree); // 4

// Build from database records
$tree = Tree\from_list(
    $records,
    fn($r) => $r['id'],
    fn($r) => $r['parent_id'],
    fn($r) => $r['name']
);

Use Cases: File systems, organizational hierarchies, DOM structures, category trees, menu systems.

Full Documentation


🕸️ Psl\Graph Component

A robust graph data structure implementation supporting both directed and undirected graphs with algorithms for analysis and pathfinding.

Features: Immutable graphs, weighted/unweighted edges, BFS/DFS traversal, shortest path (Dijkstra/BFS), topological sorting, cycle detection, flexible node types.

use Psl\Graph;

// Create and traverse graphs
$graph = Graph\directed();
$graph = Graph\add_edge($graph, 'A', 'B');
$graph = Graph\add_edge($graph, 'B', 'C');

$path = Graph\shortest_path($graph, 'A', 'C'); // ['A', 'B', 'C']
$sorted = Graph\topological_sort($graph); // ['A', 'B', 'C']

// Weighted graphs
$graph = Graph\add_edge($graph, 'NYC', 'Boston', 215);
$graph = Graph\add_edge($graph, 'NYC', 'Philadelphia', 95);
$graph = Graph\add_edge($graph, 'Philadelphia', 'Boston', 310);
$route = Graph\shortest_path($graph, 'NYC', 'Boston'); // ['NYC', 'Boston']

// Undirected graphs
$social = Graph\undirected();
$social = Graph\add_edge($social, 'Alice', 'Bob');

Use Cases: Dependency resolution, route finding, social networks, state machines, task scheduling.

Full Documentation


🔍 Reflection-Based Type Functions

New type functions for runtime validation of class members using PHP's reflection API:

  • Type\constant_name_of() - Validate constant names
  • Type\enum_case_of() - Validate enum case names
  • Type\method_name_of() - Validate method names (case-insensitive)
  • Type\property_name_of() - Validate property names

Each includes visibility-specific variants (public_*, protected_*, private_*).

use Psl\Type;

Type\method_name_of(MyClass::class)->assert('someMethod');
Type\property_name_of(MyClass::class)->assert('someProperty');
Type\public_constant_name_of(MyClass::class)->assert('SOME_CONSTANT');

Full Documentation


🛠️ Tooling Updates

  • Migration to just: Migrated from make to just for improved cross-platform compatibility and developer experience

⬆️ Dependency Updates

  • mago updated to 1.0.0-beta.32
  • actions/setup-just bumped from v2 to v3
  • Various development dependency updates

🤝 Contributors

[@veewee](https://github.com/veewee) has been added to GitHub sponsors

Full Changelog: 4.0.1...4.1.0

4.0.1

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/4.0.0...4.0.1

4.0.0

Psl Noise - 4.0.0

This release marks a major update for the PHP Standard Library, introducing several breaking changes aimed at improving strictness, consistency, and developer experience. The library is now much stricter in its type handling and serialization, and the static analysis has been migrated to a more powerful tool.

🚀 Breaking Changes

💥 Psl\Result\wrap() No Longer Unwraps Nested Results

To reduce surprising behavior, Psl\Result\wrap() will no longer automatically unwrap a Result instance returned from within the wrapped closure. It will now consistently wrap the closure's return value in a Success object, even if that value is itself a Result.

Before:

$result = Psl\Result\wrap(fn() => Psl\Result\wrap(fn() => 'hello'));
// $result is Success('hello')

After:

$result = Psl\Result\wrap(fn() => Psl\Result\wrap(fn() => 'hello'));
// $result is Success(Success('hello'))

💥 JSON Serialization for Collections

The JSON serialization for Map and Set collections has been changed to provide a more natural and predictable representation.

  • Psl\Collection\Map and Psl\Collection\MutableMap now serialize to a JSON object ({...}) in all cases, even when empty or when containing sequential integer keys. This ensures a consistent key-value structure.
  • Psl\Collection\Set and Psl\Collection\MutableSet now serialize to a JSON array ([...]), which better represents a collection of unique values.

💥 Removal of IO Intersection Interfaces

A large number of intersection interfaces in the Psl\IO and Psl\File namespaces have been removed to simplify the component's hierarchy. These interfaces were combinations of other interfaces (e.g., CloseReadHandleInterface as CloseHandleInterface&ReadHandleInterface).

Developers should now use union types or explicit interface checks where needed. For example, instead of type-hinting CloseReadHandleInterface, use CloseHandleInterface&ReadHandleInterface.

💥 Psl\sequence() Function Removed

The Psl\sequence() function, which returned the last argument it received, has been removed as it provided little practical value.

✨ New Features

Psl\Type\container()

A new container<Tk, Tv> type has been added to assert that a value is an iterable with specific key and value types. Unlike iterable(), it will coerce the value to an array.

Psl\Type\int_range()

The new int_range(int $min, int $max) type allows asserting that a value is an integer within a specified range. It supports the same coercions as the int() type.

Psl\Type\always_assert()

This new type wrapper ensures that the inner type is always asserted, even during coercion. This is useful for disabling coercion on a per-type basis.

Psl\Iter\search_with_keys() and search_with_keys_opt()

These functions provide the ability to search an iterable using a predicate that receives both the key and the value, returning the value of the first match.

♻️ Refactoring and Improvements

  • Static Analysis Migration: The project has migrated from Psalm to Mago for static analysis, resulting in stricter type checking and improved code quality. Many internal [@psalm-suppress](https://github.com/psalm-suppress) annotations have been removed.
  • Improved Type Inference: PHPDoc annotations across Dict, Iter, Regex, and Vec have been enhanced with conditional types. This allows static analysis tools to infer more precise types, especially for non-empty arrays and regex match results, reducing the need for user-land assertions.
  • Generic PHPDoc Tags: Psalm-specific tags like [@psalm-pure](https://github.com/psalm-pure) have been replaced with the more generic [@pure](https://github.com/pure) to reduce dependency on a single tool.

⬆️ Dependency Updates

  • mago has been updated to 1.0.0-beta.15.
  • actions/checkout has been bumped from v4 to v5 in GitHub Actions.
  • Other minor dependency updates.

🤝 New Contributors


Full Changelog: https://github.com/azjezz/psl/compare/3.3.0...4.0.0

3.3.0

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/3.2.0...3.3.0

3.2.0

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/3.1.0...3.2.0

3.1.0

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/3.0.2...3.1.0

3.0.2

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/3.0.1...3.0.2

3.0.1

What's Changed

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/3.0.0...3.0.1

3.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/2.9.0...3.0.0

2.9.1

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/2.9.0...2.9.1

2.9.0

What's Changed

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/2.8.0...2.9.0

2.8.0

What's Changed

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/2.7.0...2.8.0

2.7.0

What's Changed

features

  • feat(encoding): introduce Base64\Variant enum to support encoding/decoding different variants - #408 by @Gashmob

fixes, and improvements

  • fix(option): return Option<never> for Option::none() - #415 by @devnix
  • fix(str): add invariant to avoid unexpected errors when parsing an invalid UTF8 string - #410 by @devnix

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/2.6.0...2.7.0

2.6.0

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/2.5.0...2.6.0

2.5.0

What's Changed

Features

Fixes

Full Changelog: https://github.com/azjezz/psl/compare/2.4.1...2.5.0

2.4.1
2.4.0

What's Changed

Features

fixes, and improvements

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/2.3.1...2.4.0

2.3.1

What's Changed

Full Changelog: https://github.com/azjezz/psl/compare/2.3.0...2.3.1

2.3.0
2.2.0

What's Changed

features

Full Changelog: https://github.com/azjezz/psl/compare/2.1.0...2.2.0

2.1.0

What's Changed

features

fixes, and improvements

other

New Contributors

Full Changelog: https://github.com/azjezz/psl/compare/2.0.4...2.1.0

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope