Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mo4 Coding Standard Laravel Package

mayflower/mo4-coding-standard

MO4 Coding Standard is a PHP CodeSniffer ruleset extending the Symfony standard with extra rules for array alignment and formatting, property doc blocks, namespace usage, and string interpolation. Install it via Composer to enforce consistent, modern PHP coding conventions across your projects.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a framework package and not a Pint preset — it is a PHP_CodeSniffer standard named MO4 that extends the Symfony standard and layers on MO4-specific sniffs plus a curated set of Slevomat and PSR-12 rules. Treat it as a CI/lint dependency, not application code.

composer require --dev mayflower/mo4-coding-standard
./vendor/bin/phpcs -i          # must list both "MO4" and "Symfony"
./vendor/bin/phpcs --standard=MO4 app/Http/Controllers/OrderController.php
./vendor/bin/phpcbf --standard=MO4 app/Http/Controllers/OrderController.php

Version alignment first, because this is where Laravel projects break:

  • v11 requires PHP ≥ 8.1 and PHPCS ≥ 4.0. If your app or another dev tool still pins squizlabs/php_codesniffer:^3 (or an older Slevomat), Composer will not resolve. Pin mayflower/mo4-coding-standard:^10 in that case, or upgrade the whole chain.
  • The Composer installer plugin (dealerdirect/phpcodesniffer-composer-installer) registers installed_paths for you, but Composer 2.2+ will block it unless allow-plugins permits it.

Where to look first: vendor/mayflower/mo4-coding-standard/MO4/ruleset.xml. The README documents only the six MO4-native sniffs; every imported Slevomat/Symfony/PSR-12 rule is commented in that file, and it is the authoritative list of what will fail your build. Second stop is MO4/Sniffs/ if you need to understand a false positive.

First real use case: don't run it repo-wide on day one. Run it on one file you are already editing, add -s to get sniff codes, then commit a phpcs.xml.dist so the next developer and CI behave identically:

<?xml version="1.0"?>
<ruleset name="Laravel App">
  <file>app</file>
  <file>tests</file>
  <arg name="extensions" value="php"/>
  <arg name="parallel" value="8"/>
  <arg name="cache" value=".phpcs.cache"/>
  <arg name="colors"/>
  <arg value="ps"/>
  <rule ref="MO4"/>
</ruleset>

Implementation Patterns

Ratchet, don't rewrite. PHPCS has no baseline file. Adopt by excluding noisy sniffs globally first, then re-enabling one at a time:

<rule ref="MO4">
  <exclude name="SlevomatCodingStandard.Classes.ForbiddenPublicProperty"/>
  <exclude name="SlevomatCodingStandard.Functions.UnusedParameter"/>
  <exclude name="MO4.Commenting.PropertyComment"/>
</rule>

phpcs --report=source gives you a sniff-by-sniff violation count — use it to pick the highest-value, auto-fixable sniffs first (MO4.Arrays.ArrayDoubleArrowAlignment, MO4.Arrays.MultiLineArray, MO4.WhiteSpace.*, Generic.Arrays.DisallowLongArray).

Scope rules by path, not globally. Laravel code legitimately violates several imported rules in specific directories:

<!-- Livewire components, DTOs, job payloads -->
<rule ref="SlevomatCodingStandard.Classes.ForbiddenPublicProperty">
  <exclude-pattern>app/Livewire/*</exclude-pattern>
  <exclude-pattern>app/DataTransferObjects/*</exclude-pattern>
</rule>

<!-- route-model binding, middleware, policies, listeners -->
<rule ref="SlevomatCodingStandard.Functions.UnusedParameter">
  <exclude-pattern>app/Http/Controllers/*</exclude-pattern>
  <exclude-pattern>app/Policies/*</exclude-pattern>
  <exclude-pattern>app/Listeners/*</exclude-pattern>
</rule>

Also exclude bootstrap/cache, storage, vendor, and Blade files entirely (<arg name="extensions" value="php"/>).

Match the use-statement ordering to your team. MO4.Formatting.AlphabeticalUseStatements defaults to dictionary ordering, which is not what most IDE "optimize imports" does. Pick one and lock it, otherwise IDE and phpcbf will flip-flop forever:

<rule ref="MO4.Formatting.AlphabeticalUseStatements">
  <properties><property name="order" value="string-case-insensitive"/></properties>
</rule>

Composer scripts + pre-commit. Keep PHPCS out of the editor-save flow if Pint is also running, and instead wire it as an explicit gate:

"scripts": {
  "lint": "phpcs",
  "lint:fix": "phpcbf"
}

For pre-commit, feed only staged files: git diff --name-only --cached --diff-filter=ACM | grep '\.php$' | xargs -r ./vendor/bin/phpcs -s.

CI reporting. Use --report=checkstyle for GitLab/Jenkins annotations or --report=full --report-width=140 for human logs, and fail on errors only (<arg name="warning-severity" value="0"/>) since some upstream sniffs emit warnings for style-adjacent things.

Editor integration. VS Code phpcs extension / PhpStorm PHP → Quality Tools → PHP_CodeSniffer with coding standard path vendor/mayflower/mo4-coding-standard/MO4. Enable "show sniff codes" (-s) so exclusions reference exact sources rather than guesses.

Coexistence with Larastan/PHPStan is clean — different concerns. Coexistence with Pint is not clean by default: run Pint first, PHPCS read-only; never let both auto-fix in the same commit.

Gotchas and Tips

  • SlevomatCodingStandard.Namespaces.FullyQualifiedGlobalFunctions will fight Laravel/Pint convention. It wants \strlen(), Pint strips the backslash. One of them has to lose; for most Laravel teams, exclude this sniff (or scope it) rather than reformat the codebase.
  • ForbiddenPublicProperty is the single biggest source of noise in a Laravel app — Livewire, DTOs, event classes, and anything relying on public writable state. Exclude by directory, not by disabling the sniff outright.
  • MO4.Commenting.PropertyComment requires a multiline docblock with exactly one @var. Typed properties don't exempt you, and Eloquent models are usually @property on the class, not @var on properties — expect to exclude app/Models.
  • MO4.Strings.VariableInDoubleQuotedString demands braces: "{$var}" not "$var". Not fully auto-fixable in every shape (property/array access was only patched in 11.0.1/10.0.3), so budget manual fixes. Watch for "{$foo['key']}" inside heredocs and SQL strings.
  • UnnecessaryNamespaceUsage catches genuinely unused imports only, but it also fires where a class is referenced solely in a docblock type — verify with -s before deleting the use, or PHPStan will start complaining about @param types.
  • ArrayDoubleArrowAlignment produces large diffs on legacy config/translation arrays. Do it as a standalone commit and add that SHA to .git-blame-ignore-revs.
  • "MO4 is not installed" is almost always installed_paths, not the package. Diagnose with phpcs --config-show | grep installed_paths and phpcs -i; if the plugin was skipped, either allow it in config.allow-plugins or set the path manually.
  • Large repos need memory and parallelism. Add php -d memory_limit=1G vendor/bin/phpcs and <arg name="parallel" value="8"/>; commit .phpcs.cache to .gitignore, not the repo.
  • --ignore= on the CLI silently overrides your <exclude-pattern> choices — debugging "why didn't this file get checked" starts with the actual command line, including CI.
  • Extension points: the MO4 sniffs are plain PHPCS sniffs under MO4/Sniffs/; you can subclass or copy one into your own standard if you need a tweak (e.g. a different => alignment policy) instead of excluding it and getting nothing. Keep your own standard as <rule ref="MO4"/> plus your overrides so upgrades stay simple.
  • Support surface is thin (17 stars, effectively zero dependents), so there is little community documentation beyond ruleset.xml and CHANGELOG. Releases are maintained and CI/coverage-backed, but expect to read sniff source for edge cases. Pin a minor version and read the changelog on upgrade — the standard has made breaking rule changes in minor-looking releases (PHPCS 4 requirement, PHP 8.1 floor, PSR-12 import in 6.0.0).
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log