danielstjules/pho
Pho is a lightweight BDD test framework for PHP inspired by Jasmine. It offers describe/it syntax, expressive expectations, spies, and before/after hooks, making it easy to write readable, behavior-driven specs for PHP projects.
Architecture fit. Pho is a standalone BDD runner, not a Laravel package. It ships a vendor/bin/pho binary, discovers *Spec.php files, and provides a Jasmine/Mocha-style describe/it/beforeEach DSL with its own expectation library and reporter stack. There is no service provider, no facade, no PHPUnit bridge, and no awareness of Laravel's testing kernel. That means it cannot reuse TestCase, RefreshDatabase, WithoutMiddleware, HTTP assertion helpers, Bus::fake, Queue::fake, or Laravel's mocking ergonomics without us hand-rolling an equivalent harness.
Integration feasibility. Technically possible, commercially dubious. A pilot would require a custom bootstrap that instantiates Illuminate\Foundation\Application, loads the container, and manually wires database transactions and config — effectively rebuilding a meaningful slice of laravel/framework's testing traits. The larger blocker is dependency resolution: Pho's 2017-era constraints on symfony/console and related components are likely to conflict with the symfony/* versions pinned by Laravel 10/11/12, which would make composer require --dev fail outright or force unacceptable downgrades. This must be proven in a throwaway branch before any commitment.
Technical risk. High. Last release April 2017, zero dependents in the dataset, no security patching, no maintainer responsiveness, and PHP 5.4-era code that has almost certainly not been validated against PHP 8.1+. The risk is not "the tests are flaky" — it is "a dev-only dependency blocks composer install and therefore blocks production deploys." Score of 1.825 and opportunity 0.76 are consistent with a package that is interesting as prior art, not as infrastructure.
Key questions.
Stack fit. Poor. Laravel's testing story is PHPUnit and Pest; adding Pho creates a second, incompatible test toolchain with a separate assertion vocabulary, separate CI invocation, and separate reporting format. Fit is only defensible for isolated, non-critical executable specifications — for example, documentation-oriented behavioural specs for a domain module that does not touch the HTTP layer or database.
Migration path. Do not migrate existing suites. If the underlying driver is BDD readability, the correct migration is PHPUnit → Pest, which is PHPUnit-compatible, actively maintained, Laravel-first, and preserves existing test files incrementally. If Pho is being considered for a greenfield service, treat it as a spike artifact and time-box it. There is no supported upgrade path from Pho to anything, which is itself the finding.
Compatibility. Assume incompatibility until proven. The verification sequence: create a branch, composer require --dev danielstjules/pho, run composer update --dry-run against the current lockfile, then execute a trivial spec under the target PHP runtime. If Composer reports a symfony/console conflict, stop — that is a terminal finding and the evaluation ends there. Secondary checks: PHP 8.2 dynamic-property deprecations, whether the reporter output can be consumed by our CI, and whether Xdebug coverage can be attached at all.
Sequencing.
Maintenance. Adoption means ownership transfer. Upstream is dormant, so every PHP minor release becomes our problem. Budget for a fork, a compatibility patch cadence, and a documented divergence from the public package. This is a permanent tax on a tool that only affects developer experience — never revenue.
Support. No vendor, no active community, no Stack Overflow corpus of any depth. Knowledge will concentrate in whichever engineer runs the spike, creating single-owner risk. New hires arrive knowing PHPUnit and Pest; Pho syntax is easy but the custom Laravel harness is not, and that harness is exactly the part we would be inventing.
Scaling. No native parallelisation, no first-class coverage integration, no JUnit XML guarantee. As the suite grows, wall-clock time grows linearly and we either accept slower CI or invest in bespoke sharding. Two toolchains also double the surface for CI cache keys, Docker images, and dependency audits.
Failure modes.
Ramp-up. Syntax ramp-up is under a day for anyone who has seen Jasmine or Jest. Harness ramp-up is the real cost — realistically one to two sprints to get a single pilot spec running faithfully against a booted Laravel application and judged in a decision gate. That is a reasonable price for a spike and an unreasonable price for a production standard.
Recommendation. Do not adopt. Keep the dependency-conflict spike as the only committed work, use the output to justify Pest as the BDD answer, and revisit only if a maintained fork with Laravel integration appears.
How can I help you explore Laravel packages today?