Naar de inhoud
Recognized by Laravel Match je project

Razendsnelle PHP tooling met Mago

Als PHP developer ben je waarschijnlijk bekend met tools als PHPStan en Pint. Ze maken ons leven een stuk makkelijker door fouten vroegtijdig op te sporen en te zorgen voor een consistente code-stijl door de gehele codebase. Deze tools staan echter niet bekend om hun snelheid, voor sommigen een dagelijkse frustratie. Mago, een in Rust geschreven toolchain, biedt mogelijk een alternatief.

Mago VS PHPStan and Laravel Pint

Als PHP developer ben je waarschijnlijk bekend met tools als PHPStan en Pint. Ze maken ons leven een stuk makkelijker door fouten vroegtijdig op te sporen en te zorgen voor een consistente code-stijl door de gehele codebase. Deze tools staan echter niet bekend om hun snelheid, voor sommigen een dagelijkse frustratie. Mago, een in Rust geschreven toolchain, biedt mogelijk een alternatief.

Wat is Mago?

Mago is een moderne PHP toolchain geschreven in Rust, met als doel om veelgebruikte PHP tooling aanzienlijk sneller te maken. In plaats van losse tools zoals PHPStan, Pint of PHP-CS-Fixer, probeert Mago meerdere verantwoordelijkheden te combineren in één consistente CLI.

Op dit moment richt Mago zich vooral op:

  • Static analysis (vergelijkbaar met PHPStan)
  • Code formatting & linting (vergelijkbaar met Pint)
  • Snelheid en lager gebruik van resources

Voor PHP developers betekent dit mogelijk snellere feedback loops tijdens het ontwikkelen en in CI/CD pipelines.

Installatie & eerste indruk

De installatie van Mago is verrassend eenvoudig. In tegenstelling tot PHPStan of Pint is de standaard manier van installeren geen composer package, maar een binary die je globaal installeert. Dat maakt het echter wat ingewikkelder om alle dependencies van jouw project met één commando te installeren.

Gelukkig biedt Mago ook een composer package.

composer require --dev "carthage-software/mago:^1.0.3"

Na installatie is de CLI direct beschikbaar:

vendor/bin/mago --version

Op de pijnbank

Op de github pagina van Mago valt het volgende te lezen:

Mago brings speed, reliability, and an exceptional developer experience to PHP projects of all sizes.

Een veelbelovende claim en, sinds de release van versie 1.0.0 afgelopen december, eentje die ik graag op de proef stel.

Om Mago realistisch te beoordelen heb ik de tool getest in een bestaand Laravel project. Geen gefabriceerde benchmark, maar een echte codebase die al jaren wordt doorontwikkeld.

Testomgeving:

  • Laravel versie: 10 (Ik weet het)
  • PHP versie: 8.1
  • Codebase grootte:
    • Aantal PHP bestanden: ~1200
    • Regels code: ~65000
  • Machine:
    • CPU: Apple M4
    • RAM: 16GB
    • OS: macOS 15.6

Geteste tools:

  • PHPStan (level 5)
  • Laravel Pint
  • Mago (static analysis + linter)

Alle metingen zijn meerdere keren uitgevoerd en afgerond op hele seconden om ruis te beperken.

Static analysis: PHPStan vs Mago

Voor deze test kijk ik alleen hoe lang het duurt voor het opsporen van fouten en hoeveel geheugen gebruikt wordt. Ik vermeld er ook het aantal gevonden issues bij, maar eigenlijk is dat niet relevant, omdat PHPStan en Mago niet dezelfde configuraties gebruiken. Dat blijkt in de praktijk erg lastig op te zetten.

PHPStan

Als ik PHPStan draai met verbose output, dan krijg ik precies de statistieken die ik wil weten:

  • Hoe lang draaide het proces?
  • Hoeveel geheugen werd er gebruikt?
  • Hoeveel issues zijn er gevonden?

Voordat ik phpstan draaide, heb ik eerst de cache verwijderd. Op die manier is de vergelijking relevanter.

vendor/bin/phpstan clear-result-cache
vendor/bin/phpstan analyse -vvv

PHPStan runtime and memory

Resultaat:
Runtime: 71 seconden
Geheugengebruik: ~4GB
Aantal gevonden issues: 0

Mago

Bij het runnen van Mago lukt het mij jammer genoeg niet om dezelfde statistieken in de output te krijgen. Om dat te meten gebruik ik daarom een stopwatch, en houd ik het geheugengebruik handmatig in de gaten.

vendor/bin/mago analyze --reporting-format count

Mago static analyses output

Er zijn verschillende output opties, maar het count formaat is voor mij het meest overzichtelijke voor deze test. Normaliter heeft het aantal fouten in deze natuurlijk niet zo heel veel meerwaarde en wil je vooral weten waar die fouten zich bevinden.

Resultaat:
Runtime: ~1 seconde
Geheugengebruik: ~150MB
Aantal gevonden issues: 25036

Obervaties

  • Mago is significant sneller bij volledige runs en gebruikt veel minder geheugen
  • Mago mist Laravel kennis. Hierdoor ontstaan er extreem veel false positives. Iets dat PHPStan oplost met Larastan extensie.
  • Jammer genoeg kan de bestaande PHPStan-configuratie niet 1 op 1 worden geconverteerd in een regelset voor Mago. Daardoor is het aantal gevonden fouten niet goed te vergelijken.
  • De terminal is, met het standaard output formaat, langer bezig met alle error output op het scherm tonen, dan Mago bezig is met de analyse.

Code formatting: Pint vs Mago

Ook hier kijk ik alleen naar de runtime en het geheugengebruik. Net als bij de statische code analyse, heb ik geen optie gevonden om dezelfde regelset te hanteren als dat ik gewend ben van Pint. Het aantal gevonden issues is daarom niet echt relevant. Zowel Pint als Mago kunnen gevonden fouten ook automatisch repareren, maar vanwege de verschillen in configuraties test ik nu alleen het detecteren van fouten.

Laravel Pint

Wederom verwijder ik eerst de cache voor Pint, alvorens ik de analyse draai. Op die manier zijn resultaten eerlijker en beter te vergelijken.

vendor/bin/pint --test --cache-file ./pint-cache

Resultaat:
Runtime: 65 seconden
Geheugengebruik: ~150MB

Mago lint

Wat deze meting erg lastig maakte, is dat Mago zó snel is met deze analyse, dat ik met top de refresh rate naar 0.01 seconden moest wijzigen, met een screenrecorder de output moest opnemen, zodat ik deze later in video-formaat kon pauzeren. Bizar natuurlijk!

Mago linter memory

vendor/bin/mago lint --reporting-format count

Mago linter output

Resultaat:
Runtime: <1 seconde
Geheugengebruik: ~1150MB

Opvallend

  • Mago is wederom extreem snel.
  • Mago lijkt meer geheugen te gebruiken dan Pint. Nog steeds geen schokkende getallen, maar er is duidelijk gekozen voor een andere aanpak
  • Mago vindt veel meer fouten dan Pint. Of dat vooral te maken heeft met een mismatch aan configuratie is lastig om te zeggen.

Developer experience

Het is duidelijk dat Mago echt gebouwd is door developers, voor developers. Er is een duidelijke focus geweest op de performance van de toolchain en daar kunnen we duidelijk over zijn; met de snelheid van Mago zit het echt wel snor. Je kunt daarom gerust een pre-commit-hook instellen, zonder dat je daar iets van merkt. Persoonlijk vind ik Pint en PHPStan daarvoor veel te traag.

Installatie is simpel, door gebruik van composer. Er is een mago init commando, dat je moet helpen bij de configuratie. Mijn ervaring is dat Mago erkent dat er een composer.json bestand aanwezig is en daar ook wel wat mee doet, maar wat dat precies is, dat is mij niet erg duidelijk. Het is jammer dat Mago geen optie biedt om bestaande PHPStan of Pint configuraties te gebruiken voor het configureren van Mago. Op die manier zou Mago echt een drop-in vervanging kunnen zijn. Nu kost het veel tijd om Mago te configureren om te werken zoals je gewend bent. Dat is echt een gemiste kans in mijn ogen.

Mago setup wizard

Conclusie

Mago is een waanzinnig snelle toolchain voor PHP. Installatie kan op meerdere manieren en is erg makkelijk in gebruik. Omdat support voor alle Laravel magic nog ontbreekt, iets dat PHPstan wel heeft met Larastan, is de static analyser voor Laravel projecten eigenlijk nog niet geschikt. De code formatter is erg snel, maar mist nog wel de nodige configuratie-opties.

De onboarding kan wat mij betreft wel een stuk soepeler. Als Mago rekening zou houden met bestaande tools en hun respectievelijke configuratie-bestanden, zou Mago in een paar minuten geïnstalleerd en geconfigureerd kunnen zijn. Dat vergt nu echt wat handwerk.

Op dit moment is Mago daarom voor mij persoonlijk nog niet compleet genoeg om over te stappen. Het project is echter veelbelovend. Het verschil in snelheid tussen Mago en de gevestigde orde is ongekend en de voordelen daarvan zijn onmiskenbaar. Ik zal de ontwikkelingen nauwlettend volgen en hoop in de toekomst op volledige Laravel support en een makkelijkere onboarding voor bestaande projecten.

Over de auteur

Dennis Koster

Lead Developer bij Endeavour

Dennis Koster is Lead Developer bij Endeavour en bestuurslid van de Dutch Laravel Foundation. Endeavour is founding partner van de foundation en specialist in GraphQL.