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

Phploc Laravel Package

cmgmyr/phploc

Measure the size and structure of a PHP project with phploc: lines of code, cyclomatic complexity, dependencies, and class counts, right from the command line.

View on GitHub
Deep Wiki
Context7

Getting Started

cmgmyr/phploc is not a Laravel package — it is the maintained fork of sebastianbergmann/phploc, a standalone CLI binary. There is no service provider, no config file, and no Artisan command. Treat it as a shell tool you invoke from Composer scripts, a Makefile, or a small custom Artisan wrapper.

1. Install (project-local, not global)

composer require --dev cmgmyr/phploc
vendor/bin/phploc --version

Prefer local install over the README's composer global install: it pins the version per project (so your trend numbers stay comparable) and avoids the ~/.composer/vendor/bin PATH problem. If you do install globally, remember the binary lands in ~/.config/composer/vendor/bin on modern Composer, not ~/.composer/vendor/bin.

2. Point it at your code, excluding the noise

vendor/bin/phploc app \
  --exclude vendor \
  --exclude storage \
  --exclude bootstrap/cache \
  --exclude node_modules

There is no JSON output. For anything programmatic use --log-csv / --log-xml (confirm the exact flag names against vendor/bin/phploc --help on your pinned version, since option sets shifted between majors).

3. Read the four numbers that actually matter

Skip the wall of output on first run and look at:

  • LLOC — logical lines, the only size metric worth trending over raw LOC.
  • Average Class Length / Maximum Class Length — god-object candidates.
  • Maximum Method Complexity — cyclomatic complexity outliers; the average is almost always meaningless.
  • Non-Comment Lines of Code % — a proxy for docs coverage, useful as a soft signal only.

First use case: baseline your worst legacy module before you touch it. Run phploc app/Legacy --log-csv=before.csv, do the refactor, run it again into after.csv, then diff the LLOC and max-complexity rows. This is the single highest-value use: proving a refactor actually reduced size/complexity rather than just moved code around.

Implementation Patterns

Composer script for repeatable invocations

{
  "scripts": {
    "metrics": "phploc app --exclude vendor --exclude storage --exclude node_modules tests",
    "metrics:csv": "phploc app --exclude vendor --exclude storage --log-csv=build/phploc.csv"
  }
}

Then composer metrics. Keeps flags in one place so nobody hand-types a subtly different command and produces incomparable numbers.

Per-directory slicing instead of whole-app runs

Whole-repo runs on a large Laravel app give you an average that hides everything. Run per bounded context and compare:

for dir in app/Models app/Http/Controllers app/Services app/Console; do
  echo "== $dir"; vendor/bin/phploc "$dir" --exclude vendor | head -20
done

The directory with the highest maximum method complexity — not the highest LLOC — is where you start.

Wrapping it in an Artisan command

Because the output is text/CSV, the clean integration is a thin command that shells out and persists the numbers for trending:

// app/Console/Commands/CollectMetrics.php
$csv = storage_path('app/metrics/phploc-'.now()->format('Ymd').'.csv');

Process::run([
    base_path('vendor/bin/phploc'), 'app',
    '--exclude', 'vendor',
    '--exclude', 'storage',
    "--log-csv={$csv}",
])->throw();

// parse with fgetcsv() and upsert into a metrics table,
// or compare against the previous row and fail the build on regressions

Schedule it weekly, store rows keyed by commit/tag, and you get a size-and-complexity trendline for free. Note that phploc itself never exits non-zero on bad numbers — the threshold logic is yours.

CI: artifact, not gate

- run: composer metrics:csv
- uses: actions/upload-artifact@v4
  with:
    name: phploc
    path: build/phploc.csv

Upload the CSV per build. Gating directly on phploc output is brittle because the metric definitions (especially LLOC) have changed between majors; gate on your own parsed threshold with a pinned phploc version instead.

Pair it with a rules engine, don't replace one

phploc measures; it does not enforce. Use phploc to find hotspots ("which classes are 400+ lines, which methods exceed complexity 20"), then use PHPStan/PHP_CodeSniffer/PHPMD to enforce the resulting rules in CI. Reaching for phploc as a quality gate directly is the most common misfire with this tool.

--count-tests is a deliberate choice

By default test code should be excluded along with vendor. Pass --count-tests only when you genuinely want test LOC folded into the totals — for a "how much code do we maintain" figure it will distort the ratio.

Gotchas and Tips

  • No Laravel integration exists. Any evaluation claiming "Artisan-compatible" or "auto-detects app/, routes/, database/" is wrong. It walks whatever path you give it and nothing else.
  • vendor/ is not reliably excluded. Always pass --exclude vendor explicitly. A run that silently swept vendor/ will produce numbers an order of magnitude too large, and it's an easy mistake to miss because the output still looks plausible.
  • Exclude storage, bootstrap/cache, node_modules, and Blade. phploc is tokenizer-based; .blade.php files contain almost no analyzable PHP tokens and just add noise. Restrict to --suffix .php and point at real PHP directories.
  • It's a fork with a renamed namespace. SebastianBergmann\PHPLOC became Cmgmyr\PHPLOC in 8.0.0. If you had any code referencing the old classes directly (rather than the binary), it breaks. Same for anyone copy-pasting old blog posts about programmatic use.
  • Old CLI flags are gone. --names and --names-exclude were removed in 7.0.0 — use --suffix and --exclude. Stack Overflow answers referencing the removed flags are still the top hits.
  • Pin the exact version. "cmgmyr/phploc": "8.0.8", not ^8.0. LLOC and complexity counting have shifted across releases, so an unpinned range silently invalidates your historical trend comparison. This is the single most important operational rule if you're tracking numbers over time.
  • PHP constraint mismatch. composer.json says ^7.4 || ^8.0, but the transitive deps (php-file-iterator, cli-parser) have moved forward. On PHP 8.3/8.4 you generally need a recent 8.0.x release; on older PHP you may need to stay back. Check vendor/bin/phploc --version after install rather than trusting the constraint.
  • Exit code is always 0 on successful analysis. There is no --threshold, no --fail-on. Any gate must parse the output yourself — which is why --log-csv matters more than the human-readable table.
  • No JSON output. If your dashboard pipeline expects JSON, you'll be writing a CSV-to-array adapter. fgetcsv() plus array_combine() on the header row is enough; the CSV is a flat metric/value grid rather than one-row-per-class, so don't expect per-class granularity from it.
  • Averages hide everything. "Average Complexity per Class: 19.60" is useless on its own. Read minimum/maximum pairs and chase the maximums.
  • Memory/time on very large trees. There's no parallelism. On a monorepo, run it per-package/per-directory rather than once at the root, or you'll hit memory limits on the tokenizer pass.
  • Fork maturity is real risk. Low stars, zero dependents, and a short release history. Mitigate by pinning the version, vendoring/locking it in composer.lock, and keeping sebastianbergmann/phploc as a documented fallback if the fork stalls. Nothing in your workflow should depend on the fork's namespace or internals — only on the binary and its CSV.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator