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 is a modern, well-typed standard library for PHP 8.4+, inspired by HHVM’s HSL. It offers safer, predictable APIs for async, collections, networking, I/O, crypto, terminal UI, and robust data validation—replacing brittle built-ins with consistent alternatives.

View on GitHub
Deep Wiki
Context7
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport