Add first-party PHPStan analysis for Hypervel

Merged
BI
2d ago
+100275-3807

This adds hypervel/phpstan, a first-party port of Larastan for Hypervel. It replaces the separate Database, Foundation, Head and Scout extensions with one package for applications and reusable packages.

PHPStan needs more than PHP declarations to understand framework code. A model's properties come from its schema and casts; a facade's methods come from its bound service; a query's result depends on its model, builder and collection. This package supplies that information and adds checks for Hypervel's coroutine and long-running worker behavior.

The diff also includes framework fixes exposed by the improved analysis. Those changes are described separately below. Much of the remaining diff is the ported type fixtures, rules, stubs, regression coverage and source PHPDoc needed to make the analysis useful.

Analysis

  • Eloquent: infer properties from migrations, schema dumps, casts and accessors; preserve custom builders, collections, scopes and relationship types; type eager-loading callbacks by their relationship; follow factory selection and single-model versus collection results. Check column names, relationships, appended attributes and dispatch constructor arguments.
  • Framework services: resolve container bindings, facade targets, boot-registered macros, configured authentication guards and user models, filesystem and concurrency drivers, console arguments and options, views and translations. Forwarded calls retain their target signatures and return behavior.
  • Helpers and collections: infer array lookups, pulled keys, collection construction and narrowing, higher-order messages, conditional helpers, validated input and model serialization shapes. Restore fluent $this declarations where methods return the same object.
  • Queue safety: check model serialization, batch requirements, unique-job settings and dispatch inside transactions. Transaction checks account for the selected queue connection, after-commit settings, database queues and the transactional outbox.
  • Coroutine and worker safety: report cancellation handling that loses a carried cancellation, child coroutines started inside transactions, request data retained by shared services, execution-time static/configuration writes and unbounded request-keyed caches.
  • Authoring guidance: recommend attributed scopes and model/queue settings, array validation rules, testable sleeps and equivalent query operations. Existing runtime APIs remain supported. Checks have configuration switches, and automatic fixes are limited to changes whose behavior can be preserved.

The package also includes PHPStan's deprecation rules and requires a reason for each ignored diagnostic. It uses stable hypervel.* identifiers while retaining PHPStan's own identifiers.

Application and package behavior

The extension boots the application to discover its registrations. Packages use their Testbench application and testbench.yaml. Composer root and vendor discovery work under PHPStan's PHAR and across Testbench's temporary application copies.

Configuration values are inferred from source expressions, rather than frozen to the machine's environment. Application analysis includes merged package defaults. In package mode, merged package defaults do not become fixed facts about every consuming application; those reads retain the getter's declared type. Framework and workbench configuration remain typed.

Schema inference uses hypervel/schema-parser and reads migrations without executing them or connecting to a database. It follows connection selection and migration connections, preserves uncertainty for unsupported SQL or dynamic migration code, and reports unusable dumps when model analysis needs them. The schema parser now exposes the impact of SQL on existing relations and PostgreSQL types so affected facts can be invalidated without discarding unrelated schema information.

Driver inference uses declared creator return types instead of constructing backend connections. An interface-typed value retains the interface's contract; it does not acquire implementation-specific methods merely because one implementation is currently bound.

Result caching

The extension uses PHPStan's result cache and dependency APIs. Results depend on the source and runtime inputs that supplied their types: configuration, schemas, model and job metadata, relevant class declarations, boot files, environment reads and view names. Testbench copies are tracked through their stable source paths where their contents match.

Dependencies are kept narrow where possible. Editing a leaf file does not invalidate every boot-derived result, and unchanged warm runs reuse cached analysis. Changes to shared boot inputs still invalidate their consumers. Migration cache fingerprints include content so edits within one filesystem timestamp interval cannot silently reuse an old schema.

Framework fixes

  • Preserve cancellation through exception translation, cleanup and stored-failure handling across database, Redis, cache, filesystem, HTTP, gRPC, queue and other execution paths. A cleanup failure carrying cancellation must not let canceled work continue as an ordinary failure.
  • Complete HTTP, scheduler, queue, view, Scout and gRPC observations when work is canceled. OpenTelemetry and Sentry finish spans and release state while preserving known outcomes; they do not invent successful completion for work that never finished. New cancellation events expose the outcome needed by listeners.
  • Preserve inherited private properties and backed property values during job/model serialization without invoking property hooks. Apply the same complete property metadata to Horizon tags and Telescope extraction.
  • Respect fresh controller lifetimes instead of retaining their instances on routes. Keep factory eager-loading suppression local to the coroutine and honor the model's collection class.
  • Apply chain defaults without overriding job attributes, retain selected connections when partial queue fakes forward to real dispatch, and validate every job in batch chains.
  • Preserve request input values and JSON request state, correct helper and collection return contracts, and retain model serialization behavior for enums and attributed accessors.
  • Accept trait-only authenticated users in Verified events while continuing to accept users implementing only MustVerifyEmail. Explicit verification no longer fails solely because the authenticated user uses the verification trait without implementing that interface.
  • Correct schema dumping through migrations_connection, SQLite JSON number handling, pruned Reverb connection event types and textarea form validation arguments.

Package manifests also declare directly used dependencies and require the patched Symfony components included in this branch.

Adoption and compatibility

New Hypervel applications include hypervel/phpstan and phpstan/extension-installer. Both the Hypervel extension and the deprecation rules load automatically; no manual includes are needed. Run composer analyse as usual.

Existing applications and packages can install the package with:

composer require --dev hypervel/phpstan

The package requires PHPStan 2.3.5 or later. Package analysis also requires hypervel/testbench as a development dependency. Analysis boots Hypervel and therefore needs its normal Swoole runtime setup.

Existing projects using phpstan/extension-installer also load both extensions automatically. Only projects configuring PHPStan without the installer need manual includes. In those projects, replace the removed per-component extension includes with:

includes:
    - vendor/hypervel/phpstan/extension.neon
    - vendor/phpstan/phpstan-deprecation-rules/rules.neon

Deprecation reporting can be disabled through the normal include or extension-installer configuration.

Larastan-owned ignore identifiers move from larastan.* to hypervel.*; rules.modelAppends becomes hypervel.modelAppends. Remove the unsupported checkOctaneCompatibility, generalizeEnvReturnType and redisDriver parameters, along with ignores for Octane and deferred-provider diagnostics. Retained settings keep their names, but several defaults are stricter. Existing code can therefore produce additional diagnostics without losing its runtime APIs.

Some typing boundaries remain deliberate. Collections retain Laravel's covariant value type. Attribute getter/setter callbacks are treated as read-only by analysis after construction. PHPStan limitations around fixed-type custom collections and deprecations reached through proxies are documented. On PHPStan 2.3.5, the first warm run can revisit a small set of files because of internal stub-path normalization; subsequent unchanged runs reuse their results.

The new Static Analysis page covers setup, configuration, inferred types, diagnostics, fixes, legitimate exceptions and cache behavior. Related framework documentation and the Laravel porting guide are updated alongside it.

Validation

Formatting and PHPStan analysis pass for framework source, type fixtures and the application skeleton. The analyzer's rule, inference and integration tests cover application and Testbench boot, supported forwarding behavior, configuration/schema changes and diagnostic boundaries. Targeted framework regressions cover the runtime changes above, including coroutine isolation and cancellation completion.

Cache regressions compare warm results with cold analysis after relevant edits and verify reuse for unchanged application and package runs. Representative consumer checks exercised the package configuration boundary and integrations. Documentation examples, configuration defaults, identifiers and links were checked against the implementation.

[!NOTE]

Add first-party hypervel/phpstan package with framework-wide type inference and rules

  • Adds a new PHPStan extension package under src/phpstan with return-type, method, property, collector, and rule extensions covering models, collections, facades, helpers, queues, config, validation, and coroutine cancellation
  • The package boots a Hypervel application or Testbench application in its bootstrap, enabling analysis driven by real configuration, bindings, migrations, and schema dumps
  • Removes per-package PHPStan extension includes and moves analysis to the central extension in phpstan.neon.dist; adds a dedicated PHPUnit config for the PHPStan test suite
  • Alongside the analysis work, this PR unifies coroutine cancellation handling across the framework: exception selection uses Coroutine::preferCancellation(), cancellation detection uses Coroutine::causedByCancellation() (including wrapped cancellations), and canceled queue/job/request/scheduler operations now emit cancellation events and complete telemetry spans without recording spurious failures
  • Other user-facing fixes: SerializesModels now serializes parent private properties by declaring class using ClassMetadataCache::allProperties() with raw get/set accessors, Arr::pluck accepts integer keys, and Factory::createMany/makeMany return the model's custom collection type
  • Behavioral Change: per-package PHPStan extension includes are removed from composer manifests; JobAttempted gains a canceled flag so canceled attempts are no longer reported as successful; env() calls in test/teardown code are replaced with Env::get()

Macroscope summarized c458a86.