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

Phpcpd Laravel Package

systemsdk/phpcpd

A maintained fork of phpcpd, the Copy/Paste Detector for PHP. It scans your codebase for duplicated code using tokenization, reports clones with file and line info, and supports configurable thresholds and CI integration to help keep projects clean.

Deep Wiki
Context7

Getting Started

Install as a dev dependency and invoke the bundled binary — there is no Laravel service provider, facade, or config file to publish:

composer require --dev systemsdk/phpcpd
vendor/bin/phpcpd --help
vendor/bin/phpcpd --version

First run against the code that actually matters, with defaults (--min-lines=5, --min-tokens=70) and obvious noise excluded:

vendor/bin/phpcpd app/ --progress \
  --exclude vendor --exclude storage --exclude bootstrap/cache \
  --log-pmd build/cpd.xml

Where to look first, in order: the README for the fork's supported PHP range and any divergences from the abandoned sebastianbergmann/phpcpd; --help output for the exact option set in your installed version; and the CHANGELOG, since this is a maintained fork of a deprecated tool and behavior (notably exit codes) has shifted across majors. A good first use case is a one-off baseline scan of app/ to see whether duplication is a real problem before wiring anything into CI — many Laravel codebases discover the findings are concentrated in a handful of god-services or near-identical FormRequests.

Implementation Patterns

CI as a reporting gate, not a build-breaker (at first). Emit --log-pmd=build/cpd.xml as an artifact and consume it with the Jenkins CPD plugin, SonarQube, or a small parser. This gives trend visibility without blocking merges on day one. Once the baseline is understood, decide deliberately whether a non-zero exit should fail the pipeline — verify the exit-code semantics of your pinned version rather than assuming.

Ratchet the thresholds. Don't start at the defaults. Begin with something permissive (--min-lines=20 --min-tokens=150) so only egregious clones surface, get the count to zero or an accepted level, then lower the thresholds incrementally in follow-up PRs. This mirrors how teams adopt PHPStan levels and avoids a 400-finding wall that everyone ignores.

Composer scripts for local ergonomics. Wire the exact invocation into composer.json so developers run the same command CI does:

"scripts": {
  "cpd": "phpcpd app/ --exclude vendor --progress",
  "cpd:ci": "phpcpd app/ --log-pmd build/cpd.xml --exclude vendor"
}

Scope deliberately. Exclude tests/ (duplication in fixtures and data providers is usually intentional), database/migrations/ (structurally near-identical by design), config/, and any generated code. Use --exclude for directory prefixes and --regexps-exclude for path patterns when the noise lives in a naming convention rather than a fixed directory.

Use --fuzzy for renamed-variable clones. Without it, two blocks that differ only in local variable names won't match. Turn it on for a second pass when hunting copy-paste that has already drifted slightly, but keep the non-fuzzy run as your primary gate.

The tool takes one directory. For multi-root scans (app/, routes/, packages/), run it once per directory in a loop and merge the PMD XML, or accept a broader root with liberal excludes. There are no glob arguments.

Pair it with a diff-aware pre-commit hook. Because there's no incremental mode, the practical pattern is a pre-push script that runs the full scan only on the changed top-level directories, or simply relies on the CI artifact and reviews new entries between builds.

Gotchas and Tips

  • Upstream is abandoned; this is a community fork. Pin the version in composer.json and check PHP compatibility on every upgrade. Do not expect rapid fixes, and keep a fallback plan (PHPStan's duplication rules, jscpd, or a custom tokenizer) if the fork stalls.
  • Exit codes are version-dependent. Some releases return non-zero when clones are found, older ones always returned 0. Confirm with echo $? before you make it a hard gate; otherwise your "quality gate" silently passes forever.
  • Detection is token-literal. Whitespace and formatting normalization go only so far; comments and string literals break matches. --fuzzy fuzzes variable names only — not method names, not literals. Expect to miss clones that were reformatted by a style fixer.
  • There is no inline suppression. You cannot annotate a block with @cpd-ignore. Suppression means excludes, regexps, or raising thresholds — which is why excluding tests/ and generated code up front matters so much.
  • Generated and boilerplate code dominates false positives. Getters/setters, DTOs, policy stubs, and repetitive migration files will top the report. Exclude them or accept them explicitly; do not "fix" duplication that exists for framework or schema reasons.
  • Large repos are slow and memory-hungry. Tokenizing the whole tree is a full parse. Keep the scan to app/ and use --progress locally so developers don't think it hung.
  • --names defaults to *.php. If you have .blade.php or other extensions worth scanning, pass them explicitly; conversely, tighten --names if you want to skip view templates.
  • Detection is not remediation. The tool never rewrites code. Treat findings as a review prompt — some duplication is the cheaper option, and extracting a shared abstraction across two unrelated domains is often worse than the clone.
  • Text output is human-only. For anything automated, always go through --log-pmd; scraping the console table is fragile across versions.
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.
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json
refinery29/php-cs-fixer-config
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules