Mago 1.0.0-beta.33
This release introduces a powerful and highly-requested set of new analysis features for detecting missing type hints. We've also made the analyzer significantly smarter at handling superglobals and boolean comparisons, landed a raft of critical bug fixes that improve type-narrowing, and shipped a major performance optimization for large projects.
✨ New: Missing Type Hint Detection
The analyzer can now detect and report missing type hints for constants, properties, parameters, and return types, helping you improve the strictness and reliability of your codebase. This new analyzer-based feature is more powerful and accurate than the old linter rules it replaces.
- Comprehensive Checking: The analyzer will report
missing-constant-type
,missing-property-type
,missing-parameter-type
, andmissing-return-type
issues. - Highly Configurable: You have fine-grained control via new settings in your
mago.toml
:check-missing-type-hints
: The main switch to enable/disable this feature.check-closure-missing-type-hints
: Toggles checks specifically for closures.check-arrow-function-missing-type-hints
: Toggles checks specifically for arrow functions.
- Intelligent & Low-Noise: The analyzer is smart enough to avoid common false positives. It automatically ignores:
- Methods/properties that override a parent that also lacks a type hint.
- Parameters prefixed with
$_
(a common convention for unused variables). - Constructors (
__construct
) and destructors (__destruct
) for return type checks.
⚡️ Major Performance Gains for Large Projects
A significant performance bottleneck in the type reconciliation logic for sealed classes has been eliminated. The impact of this optimization is most dramatic on very large projects that make extensive use of sealed type hierarchies with many instanceof
checks.
When analyzing a large codebase like the Symfony framework, this release is over 6x faster than the previous version.
Symfony Benchmarks:
Benchmark 1: mago-32 analyze --reporting-format count
Time (mean ± σ): 8.894 s ± 0.326 s [User: 11.398 s, System: 4.137 s]
Range (min … max): 8.509 s … 9.508 s 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 2: mago-33 analyze --reporting-format count
Time (mean ± σ): 1.455 s ± 0.071 s [User: 7.138 s, System: 1.680 s]
Range (min … max): 1.351 s … 1.536 s 10 runs
Warning: Ignoring non-zero exit code.
Summary
mago-33 analyze --reporting-format count ran
6.11 ± 0.37 times faster than mago-32 analyze --reporting-format count
For smaller projects or codebases that do not heavily rely on this specific pattern (like PSL or WordPress), the performance will remain similar to the already fast previous versions. This targeted optimization ensures that Mago scales efficiently, even for the most complex architectural patterns, without introducing regressions elsewhere.
Psl Benchmarks:
Benchmark 1: mago-32 --config config/mago.toml analyze
Time (mean ± σ): 233.6 ms ± 13.4 ms [User: 612.0 ms, System: 400.4 ms]
Range (min … max): 224.4 ms … 271.2 ms 10 runs
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
Benchmark 2: mago-33 --config config/mago.toml analyze
Time (mean ± σ): 224.4 ms ± 8.4 ms [User: 631.4 ms, System: 402.6 ms]
Range (min … max): 214.0 ms … 237.2 ms 10 runs
Summary
mago-33 --config config/mago.toml analyze ran
1.04 ± 0.07 times faster than mago-32 --config config/mago.toml analyze
WordPress Benchmarks:
Benchmark 1: mago-32 analyze --reporting-format count
Time (mean ± σ): 3.853 s ± 0.147 s [User: 15.298 s, System: 0.752 s]
Range (min … max): 3.467 s … 3.946 s 10 runs
Warning: Ignoring non-zero exit code.
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
Benchmark 2: mago-33 analyze --reporting-format count
Time (mean ± σ): 3.832 s ± 0.200 s [User: 16.264 s, System: 0.758 s]
Range (min … max): 3.488 s … 3.991 s 10 runs
Warning: Ignoring non-zero exit code.
Summary
mago-33 analyze --reporting-format count ran
1.01 ± 0.07 times faster than mago-32 analyze --reporting-format count
🚀 Major Analyzer Improvements
Smarter Superglobal Handling
The analyzer is now much smarter about superglobals ($_GET
, $_SERVER
, etc.). They are now pre-registered in all scopes by default, which resolves a major pain point where type narrowing on superglobal array keys (e.g., in if (isset($_GET['user']))
) would fail. You can control this with the new register-super-globals
setting.
Upgraded: Type-Aware Boolean Comparison
The no-boolean-literal-comparison
check has been moved from the linter to the analyzer. Because the analyzer is type-aware, it can now avoid false positives by understanding the context. For example, it will correctly allow a check like $foo === false
if the type of $foo
is a union that includes false
(e.g., false|string
).
🐞 Other Bug Fixes
- Critical Analysis Fixes:
- Resolved several bugs related to correctly resolving
static
return types, detecting callables in::class
strings, and handling chained null checks. (#511, #549, #577) - Corrected object type subtraction logic for non-sealed class hierarchies, improving type narrowing.
- Fixed a bug where
isset()
was not correctly narrowing a nullable array key to non-null within a conditional block. (#573)
- Resolved several bugs related to correctly resolving
⚠️ Deprecations
The following linter rules are now deprecated in favor of the more powerful analyzer-based checks. They will be removed in a future release.
constant-type
parameter-type
property-type
return-type
no-boolean-literal-comparison
🤝 New Contributors
Closed Issues
Full Changelog: 1.0.0-beta.32...1.0.0-beta.33