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

Lines Of Code Laravel Package

sebastian/lines-of-code

A lightweight PHP library from Sebastian Bergmann for counting lines of code in PHP source files, reporting logical and physical line counts. Used by PHPUnit's code coverage tooling and handy for building metrics, reports, and static analysis tools.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. sebastian/lines-of-code is a stateless, framework-agnostic, single-purpose library: you hand Counter::count() a file path and get back an immutable value object exposing linesOfCode, commentLinesOfCode, and nonCommentLinesOfCode. There are no service-provider bindings, no configuration surface, no I/O beyond reading the file, and no persistence. Architecturally that puts it in the build-time analytics tier of a Laravel system — an Artisan command, a scheduled reporting job, a CI step, a PR-comment bot — and explicitly not in the request lifecycle. For a TPM the consequence is favorable: zero production latency, zero runtime blast radius, no security review of an inbound attack surface. The decision is therefore almost entirely a process decision (what the number is for, who owns the threshold, what decision it feeds), not a technical one.

Integration feasibility. High. Installation is a single Composer line, and it should be --dev unless a reporting job ships in the deployed artifact. The PoC is genuinely half a day: one recursive directory walk, an exclusion list, an aggregation, and an output format. Two caveats materially shape the estimate:

  • The "0 dependents" figure is almost certainly a dataset artifact. This package is a transitive dependency of phpunit/php-code-coverage, so it is very likely already in your composer.lock on any Laravel project running PHPUnit. Run composer why sebastian/lines-of-code before scoping — if it is already present, the marginal dependency and procurement risk is effectively nil and the go/no-go conversation changes shape.
  • The README's "three lines" framing overstates readiness. The public API is per-file. Recursive traversal, vendor/ and .gitignore exclusion, aggregation by module, and the tests for all of that are your code. Budget one to two days of engineering including validation, not one hour.

Technical risk. Four risks, ordered by probability of derailing the initiative:

# Risk Likelihood Impact Mitigation
1 PHP version floor. 5.x dropped PHP 8.3 support (requires 8.4+); 4.x dropped 8.2; 3.x targets 8.2. Many Laravel LTS-track apps cannot take the current major without a runtime upgrade. High Blocks adoption of latest line Pin deliberately: 5.x on 8.4+, 4.x on 8.3, 3.x on 8.2. Or run the counter in an isolated CI container pinned to 8.4 and keep app runtimes untouched.
2 Counting correctness. 4.0.1 and 5.0.1 fix the same defect — multi-comment lines double-counted, producing negative non-comment LOC. 5.0.2 followed with a guard forcing $linesOfCode positive. A metric that can return impossible values is a governance hazard if it gates merges. Medium Credibility loss on first bad dashboard Golden-file validation against a hand-counted sample and against cloc before any enforcement. Assert non-negativity in your own wrapper.
3 Parser coupling. It depends on nikic/php-parser, shared with PHPStan, PHP-CS-Fixer, and Rector. (Note: internal docs describe it alternately as a tokenizer and a parser — in practice it is parser/tokenizer-based, which is exactly why heredocs and block comments are handled correctly, and exactly why it couples you to that stack.) Medium A broken composer update, not a broken metric — noisy and diagnosable Align the nikic/php-parser constraint with the existing static-analysis stack; let Composer resolve before locking a version.
4 Scope blindness. PHP source only. Blade templates, Livewire/Inertia, JS/Vue/React, migrations, and config are invisible. On a full-stack Laravel team this systematically under-reports delivered work. Certain First dashboard gets challenged and loses authority State the boundary in the dashboard's own subtitle: "PHP application code only." Pair with a polyglot counter (tokei/cloc) if the audience expects whole-repo totals.

Key questions for the team.

  • What decision does this number inform — a refactor-prioritization case, a capacity argument, a merge warning, or an onboarding heat map? A gate needs accuracy and a frozen baseline; a trend needs only directional consistency.
  • Where does it run — CI (no PHP 8.4 requirement on developer laptops), an Artisan command (developer convenience), or both? Recommend CI first.
  • Who owns the threshold and the exception path when a legitimate PR exceeds it?
  • Will results be persisted? Without storage there is no trend line, and a trend is the only version of this metric that is decision-grade. A one-shot count is trivia.
  • Are we prepared to state, in writing, that this is never an individual or team performance measure?

A governance caveat a TPM must raise explicitly. LOC is a proxy metric and degrades badly under pressure. The moment it becomes a per-developer productivity score, engineers optimize for it — splitting PRs, stripping comments (which this library conveniently counts separately, inviting a "comment density" score that is worse than useless), deleting scaffolding. The signal inverts and the dashboard becomes actively harmful. Used as a team-level trend against a rolling baseline, it is a cheap, defensible input to refactoring and capacity conversations. Get that sentence into the rollout doc before the first dashboard ships, co-signed by the engineering manager who will be asked about it in a performance calibration.

Integration Approach

Stack fit. Strong on three Laravel-native surfaces, poor on one:

Surface Fit Rationale
Artisan command (metrics:loc) Strong Idiomatic, discoverable, zero infrastructure, no new deployment artifact. Recommended first deliverable.
PHPUnit assertion / test guard Strong Good for a narrow, high-value check: "app/Modules/Billing must not exceed N logical LOC without review." Keep it markTestSkipped-adjacent (warn-only) initially.
Scheduled job + persisted history Moderate The only path to a trend line. Requires a table, a migration, and an owner. Justify it against "we already have a BI tool that could ingest a CSV."
HTTP endpoint / request lifecycle Avoid Reads the filesystem synchronously and has no business in a user-facing request. Any dashboard should read persisted results, not count on demand.

Migration path. There is nothing to migrate from if this replaces an ad-hoc wc -l script or a spreadsheet — and nothing to migrate to if you already have SonarQube, CodeClimate, or PHPMetrics producing LOC data, in which case adding this creates a second source of truth and a reconciliation argument you do not want in a steering meeting. The realistic migration is: retire informal size anecdotes, not retire a tool. Sequence it as additive first, and only decommission the shell script once the new numbers are validated and someone actually reads them weekly.

Compatibility. Three axes to check before committing:

  1. PHP runtime — 5.x needs 8.4+, 4.x needs 8.3, 3.x needs 8.2. Choose the line, don't float.
  2. nikic/php-parser — confirm the major version this package pulls matches what PHPStan / PHP-CS-Fixer / Rector already require in the lockfile.
  3. PHPUnit — since the package already arrives transitively via phpunit/php-code-coverage, check whether an explicit direct dependency is even necessary or whether you are just formalizing a transitive one. Formalizing it (adding it explicitly with a pinned constraint) is generally the right move — it prevents a PHPUnit upgrade from silently removing a capability you now depend on.

Sequencing. Four steps, each independently shippable and independently abortable:

  1. Spike (½ day). Install pinned to the runtime-appropriate major; count three known files; reconcile against a hand count and against cloc. If they disagree and you cannot explain why, stop here.
  2. Artisan command (1 day). Directory walk with explicit exclusions (vendor/, node_modules/, storage/, generated code). Emit a table and a --json flag. No persistence.
  3. Persist + trend (1–2 days). Nightly scheduled job writes per-module counts. Only build this after step 2 has been run manually at least twice and someone asked "how does this compare to last month?"
  4. Soft CI signal (policy, not code). PR comment or warn-only check against the rolling baseline, with a written exception path. Hold this in warn-only for at least one quarter before anyone proposes making it blocking — and treat any such proposal as a signal to re-examine why, not as a natural maturation.

Do not skip to step 4. The failure mode of this package is not technical; it is an unvalidated number acquiring policy authority.

Operational Impact

Maintenance. Very low — and this is the package's strongest operational argument. It is a roughly hundred-line component maintained by the PHPUnit maintainer, versioned with clear semantic major releases, CI- and coverage-gated. The maintenance cost sits almost entirely in your wrapper (traversal rules, exclusion lists, aggregation, storage schema), not in the dependency. Expect to touch your wrapper when repositories are restructured and essentially never to touch the library. Budget a few hours a year for dependency bumps.

Support. No vendor, no SLA, no paid tier — BSD-3-Clause, best-effort open source. For a build-time metrics tool that is acceptable; for anything customer-facing it would not be. Internalize this: if the package is abandoned or a future major takes a direction you cannot follow, the exit is trivial (the output is three integers; swap in tokei or a tokenizer you write in an afternoon). Exit cost is near zero, which is exactly what justifies the low-risk "optional infrastructure" framing. The real support burden is social: someone must own "what does this number mean" and answer the question in every review where it appears.

Scaling. Compute scales linearly and trivially — counting a 50K-file tree is a CI-minute-scale job, not an infrastructure concern. What does not scale is the narrative. Two specific scaling limits:

  • Module granularity is manual. As the codebase grows, the value of the metric shifts from a single total to per-module deltas. That requires a maintained mapping from directories to product domains — an ongoing, low-grade editorial task with a named owner.
  • Single-language scope becomes more visible at scale. In a monorepo with a growing frontend, PHP-only counts describe a shrinking share of the system. Re-baseline or pair with a polyglot counter before leadership reads a suspiciously flat line as "we stopped building."

Failure modes. Five, with detection:

Failure Symptom Detection / response
Negative or zero non-comment LOC on comment-heavy files Impossible values in output Assert >= 0 and >= physical-count invariants in your wrapper; fail the job loudly rather than writing bad rows. Precedent exists in 4.0.1/5.0.1/5.0.2.
Silent misconfiguration of exclusions Total jumps when vendor/ ships in a release tarball, or drops when a path is over-excluded Assert total is within ±X% of prior run; alert on step changes, not just on thresholds.
Parser version conflict composer update fails; CI red for an unrelated reason Standard dependency hygiene; keep the constraint aligned with the static-analysis stack.
Metric gaming Comment density falls, PR size fragments, scaffolding deleted The most dangerous failure because it looks like improvement. Never publish per-person. Review the trend, not the leaderboard.
Dashboard abandonment Nobody opens it after week three Pre-commit to a named consumer and a monthly review cadence, or don't build step 3 at all. An unread dashboard is pure carrying cost.

Ramp-up. Minimal for engineers — one constructor call, one method, one value object; a competent Laravel developer is productive in under an hour with the README alone. The real ramp-up cost is organizational, not technical, and should be planned as such:

  • Engineering: ~1 hour to use the library, ~1 day to build the traversal wrapper responsibly.
  • TPM / analytics owner: the harder half-day — defining the baseline, the module map, the review cadence, and the written "not a performance metric" policy.
  • Stakeholders: one 15-minute briefing that establishes what the number is, what it excludes (Blade, JS, migrations, config), and what decision it will and will not be used for.

Bottom line for a TPM: treat this as optional internal infrastructure with near-zero exit cost, not a roadmap item. It is worth adopting only if you specifically need PHP-aware, in-process LOC — including logical/statement counts — feeding a trend you will actually review monthly. If the requirement is merely "a number in a dashboard," cloc in CI gets you 80% of the value for near-zero engineering. The adoption decision should be made on the strength of the decision the trend feeds, not on the library's merits — those are settled and unremarkable, which is precisely the compliment this dependency deserves.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route