CLI-детектор копіпасту для PHP 8.5+

Перекладено ШІ 0 Laravel News 04 липня, 2026

Новий інструмент phpcpd-next допомагає миттєво виявити приховані дублікати коду, які зазвичай вислизають від уваги під час рев’ю. Дізнайтеся, як автоматизувати боротьбу з копіпастом у Laravel та інтегрувати інтелектуальний аналіз прямо у ваші PHPUnit-тести.

phpcpd-next аналізує ваш PHP-код на наявність дубльованих фрагментів. Він знаходить копіпаст, який легко пропустити під час рев'ю, але складно підтримувати в майбутньому.

Проєкт розвиває Лучано Федеріко Перейра як наступника архівованого інструменту phpcpd Себастьяна Бергманна. Він є повністю сумісною заміною (drop-in replacement) і використовує ту саму команду phpcpd.

Головне нововведення: інструмент розпізнає не лише ідентичні копії. Він помічає дублікати навіть тоді, коли рядки поміняли місцями або додали/видали окремі інструкції між однаковими блоками:

  • Три рушії детекції — Rabin-Karp (точні збіги), TokenBag (змінений порядок) та опціональне суфіксне дерево (gapped Type-3) із додатковим --fuzzy режимом, що ігнорує назви змінних.
  • Чотири формати виводу — текст у консолі, PMD-CPD XML, JSON та SARIF 2.1.0 для інтеграції з GitHub Code Scanning.
  • Headless API для запуску перевірки безпосередньо в коді, а також PHPUnit trait, який перетворює пошук дублікатів на частину тестів.
  • Інструменти для CI — зрозумілі exit codes, кешування результатів та інкрементальна індексація змінених файлів.
  • Пресети для фреймворків — зокрема для Laravel, з можливістю перевизначити налаштування через CLI.
  • PHP 8.5+ без жодних сторонніх залежностей у Composer runtime та стабільні детерміновані результати.

# Три рушії, що працюють одночасно

Більшість подібних інструментів шукають лише повні копії. phpcpd-next за замовчуванням запускає Rabin-Karp (безперервні збіги) та TokenBag (перемішані рядки). Алгоритм суфіксного дерева для пошуку складних дублікатів із пропусками вмикається окремо:

# Стандартно: точний пошук + перевірка порядку
phpcpd src/
 
# Тільки Rabin-Karp (швидше, без детекції зміненого порядку)
phpcpd --rk src/
 
# Пошук дублікатів із пропусками (Type-3) через суфіксне дерево
phpcpd --algorithm=suffixtree src/

Консольний вивід не просто перелічує рядки, а вказує на дубльовані фрагменти та пропонує рефакторинг:

Found 2 code clones with 21 duplicated lines in 2 files:
 
  - app/Services/Billing.php:12-33 (21 lines)
    app/Services/Invoicing.php:40-61
    → Consider extracting the shared lines into a reusable method or constant.
 
37.50% duplicated lines out of 56 total lines of code.

# SARIF для GitHub Code Scanning

Окрім форматів PMD-CPD XML та JSON, phpcpd-next підтримує SARIF 2.1.0. Це дозволяє відображати знайдені копії прямо у вкладці Security на GitHub. Неточні збіги отримують статус warning, а повні — note:

- name: Detect duplicated code
  run: vendor/bin/phpcpd --log-sarif=phpcpd.sarif src/ || true
 
- name: Upload results
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: phpcpd.sarif

# Headless API та PHPUnit Assertions

Інструмент можна використовувати як бібліотеку через статичний виклик detect() — без консольних команд та файлів звітів:

use LucianoPereira\PhpcpdNext\Phpcpd;
 
$clones = Phpcpd::detect(
    paths: 'app',
    minTokens: 60,
    algorithm: null,       // null = Rabin-Karp + TokenBag
    preset: 'laravel',
);
 
foreach ($clones as $clone) {
    echo $clone->numberOfLines(), " lines\n";
}

Завдяки спеціальному trait перевірку на дублікати можна перетворити на тест, що не дозволить регресіям потрапити в код:

use LucianoPereira\PhpcpdNext\PHPUnit\AssertNoDuplication;
use PHPUnit\Framework\TestCase;
 
final class DuplicationTest extends TestCase
{
    use AssertNoDuplication;
 
    public function test_app_is_dry(): void
    {
        $this->assertNoDuplication(__DIR__ . '/../app', minTokens: 70);
    }
}

# Інкрементальне кешування для CI

Для великих проєктів прапорець --cache зберігає результати на основі конфігурації та хешу файлів. Режим --incremental працює ще глибше: він аналізує лише змінені файли, підтягуючи решту з індексу (лише для Rabin-Karp):

- uses: actions/cache@v4
  with:
    path: .phpcpd-cache
    key: phpcpd-${{ hashFiles('**/*.php') }}
    restore-keys: phpcpd-
- run: vendor/bin/phpcpd --incremental --cache-dir .phpcpd-cache src/

# Встановлення

Для роботи потрібні PHP 8.5+, розширення ext-dom та ext-mbstring. Інструмент встановлюється як dev-залежність:

composer require --dev phpcpd-next/phpcpd
vendor/bin/phpcpd src/

Пресет для Laravel автоматично сканує директорії app, routes, database та config, ігноруючи папку vendor, Blade-шаблони, міграції та файли IDE-helper:

vendor/bin/phpcpd --preset=laravel app/Services --min-tokens=60

Вихідний код та повна документація доступні на GitHub.

Популярні

Інше, що варто прочитати

Використання повнотекстового пошуку в Laravel
178 Оновлено 26 червня, 2026

Використання повнотекстового пошуку в Laravel

Laravel пропонує потужні можливості повнотекстового пошуку за допомогою методів whereFullText та orWhereFullText, що дозволяють здійснювати складні запити до бази даних. Дізнайтеся, як реалізувати ефективний пошук для вашого блогу чи системи управління контентом

22 Оновлено 26 червня, 2026

Налаштування Xdebug з Docker та PHP 8.4 всього за одну хвилину

Встановлення Xdebug може бути складним завданням, але в цій статті ми розкриємо, як швидко та просто налаштувати його за допомогою Docker на прикладі Laravel. Дочитайте до кінця, щоб дізнатися, як за кілька хвилин зробити Xdebug вашим надійним помічником у розробці

38 Оновлено 26 червня, 2026

4 поширені помилки Vite у Laravel

Використання Vite для створення фронтенд-ресурсів у вашому додатку Laravel може бути захоплюючим, але іноді ви можете стикнутися з певними помилками. У цій статті ми розглянемо чотири поширені помилки, з якими ви можете зіткнутися, а також підкажемо способи їх усунення, щоб ви могли знову зосередитися на розробці вашого додатку