PHP port of stackblitz/alien-signals 3.1.2. Line-for-line, same algorithm, same flags, same DLL semantics.
alien-signals is a small reactive-signals library: signals, computed
values, effects, an automatic dependency graph with pull-on-read and
push-mark-dirty propagation. It was previously available only on
JavaScript runtimes via npm. This artifact ports the same algorithm to
PHP 8.1+ so any PHP consumer can use it without a JS bridge.
src/
ReactiveFlags.php Bit-flag constants
ReactiveNode.php Base node (deps, depsTail, subs, subsTail, flags)
Link.php Doubly-linked-list edge between dep and sub
ReactiveSystem.php Algorithm core: link, unlink, propagate,
checkDirty, shallowPropagate, startTracking,
endTracking (port of system.ts)
SignalNode.php value + previousValue
ComputedNode.php value + getter
EffectNode.php fn
Signal.php User-facing get / set
Computed.php User-facing get
Effect.php User-facing stop
Signals.php Static facade: signal, computed, effect, batch,
untrack, effectScope, trigger (port of index.ts)
use Hbt\AlienSignals\Signals;
$a = Signals::signal(1);
$b = Signals::computed(fn($prev) => $a->get() * 2);
$e = Signals::effect(fn() => print($b->get() . "\n"));
$a->set(5); // prints 10
Signals::batch(function () use ($a) {
$a->set(7);
$a->set(9);
}); // prints 18 once
$e->stop();Composer (once published or via path repository):
{
"require": {
"hbt/alien-signals": "^3.1.2"
}
}For local development, point composer at the path:
{
"repositories": [
{ "type": "path", "url": "../alien-signals-php" }
],
"require": {
"hbt/alien-signals": "*"
}
}21 PHPUnit tests cover the load-bearing cases ported from upstream's Vitest spec files:
- signal read/write semantics, value-equality skip
- computed memoisation and chained propagation
- effect lifecycle (eager run, dispose, nested stop)
- batch coalescing
- untrack via
Signals::untrackand via directsetActiveSub - diamond topology — both signal-only and computed-via-checkDirty
- signal-revert: writing then reverting must NOT force recompute
- effectScope dispose
vendor/bin/phpunit
OK (21 tests, 57 assertions)
Single-threaded per request, same as upstream. The shared Signals
static state (activeSub, activeScope, batchDepth, notify queue)
is request-scoped under typical fpm / cli usage. Use
Signals::reset() to clear state between tests or REPL evaluations
within a single process.
Tracks upstream npm. When stackblitz publishes a new version, this artifact moves to the same version with the corresponding system.ts and index.ts changes ported.
MIT — same as upstream.