Оновлення PHP успішне лише тоді, коли застосунок і надалі виконує роботу, від якої залежать його користувачі. Зелене встановлення залежностей не доводить, що пошук знаходить правильні записи, перекладена сторінка зберігає свою адресу або завантажене зображення переживає наступний реліз. Тому модернізація починається зі спостережуваної поведінки та операційних обмежень, а не із заміни фреймворку.
DigiSpace дає конкретний приклад: застосунок Laravel із публічним сайтом на Blade, локалізованим контентом у базі даних та адмін-панеллю Filament. Репозиторій також зберігає залежності Inertia і Vue. Це не означає, що кожен екран адмінки використовує однаковий стек. Точна оцінка простежує маршрути та представлення, що фактично використовуються, замість трактування списку залежностей як повної карти архітектури.
Цільовий бізнес-результат — послідовність змін, які можна перевіряти незалежно. Регресійний тест пошуку захищає поведінку каталогу; оновлення контенту зберігає редакційні поля, які йому не належать; а перевірка деплою верифікує результуючу сторінку та ресурс. Ці контролі роблять зміну рецензованою, але не доводять, що кожен реліз оборотний.
Встановіть базову лінію версій та інтеграцій
Перевірений маніфест DigiSpace вимагає PHP ^8.3, Laravel ^13.0 і PHPUnit ^11.0. Це обмеження залежностей, а не твердження, що кожне середовище працює на ідентичній патч-версії. Перед оновленням запишіть встановлені пакети, runtime PHP, розширення, рушій бази даних і конфігурацію воркерів на фактичній цілі.
Інвентаризуйте також зовнішні межі застосунку. DigiSpace включає залежності сховища, моніторингу, CRM і reCAPTCHA. Зміна runtime може залишити звичайні сторінки робочими, поки вихідний API-запит, завантажений об'єкт чи запланована команда падає. Базова лінія має ідентифікувати, хто володіє кожною інтеграцією і як її можна перевірити без надсилання реальних даних клієнтів чи створення дубльованих бізнес-записів.
Офіційний посібник міграції PHP 8.2–8.3 розділяє нові функції від несумісної та застарілої поведінки. Він покриває саме цей крок версій. Застосунок, що стартує на ранішому релізі PHP, потребує також проміжних посібників. PHP 8.3 — мінімальне обмеження цього проєкту, а не універсальна рекомендація для нової системи.
Порівняйте три підходи до модернізації
Оновлення на місці зберігає поточну архітектуру та коригує несумісні залежності й код. Воно має найменшу продуктову зміну, коли структура ще пасує бізнесу. Його обмеження в тому, що воно може зберегти зв'язність, яка робить наступні функції дорогими. Підтримка версій і якість архітектури — пов'язані, але не однакові задачі.
Інкрементальна заміна вводить межу навколо одного workflow і змінює цей workflow, поки решта лишається у використанні. Пояснення Strangler Fig Мартіна Фаулера описує цей підхід і його перехідну ціну. Тимчасові адаптери та правила маршрутизації — реальна робота; їм потрібен власник і остаточне видалення, а не перетворення на ще один постійний шар.
Повне переписування може мати сенс, коли продукт чи модель даних фундаментально змінюються. Воно також створює велику проблему прийняття та міграції: незадокументовану поведінку треба відкрити, стару й нову системи може знадобитися підтримувати паралельно, а дані мають перетнути чітко визначене перемикання. Жоден із цих обов'язків не зникає через те, що заміна використовує новіший фреймворк.
Починайте з реальної видимої користувачеві межі
Пошук послуг DigiSpace — корисний обмежений приклад. Застосунок зберігає і категоризовані послуги каталогу, і внутрішні рядки функцій, пов'язані з пакетами цін. Пошук має повертати перші, коли вони збігаються. Він не повинен рекламувати рядок функції, що не має публічної категорії послуги.
HeaderSearchTest фіксує цю відмінність. Нижче — фактичний метод тесту, відформатований у кілька рядків для читабельності. Він належить тестовому класу репозиторію, який імпортує дві моделі, використовує RefreshDatabase і SeedsPublicSite та викликає seedPublicSite() під час налаштування. Це не самостійний PHP-скрипт:
public function test_service_search_lists_matching_categorised_services(): void
{
$category = ServiceCategory::create(['name' => 'Web', 'slug' => 'web']);
Service::create([
'title' => 'Laravel development',
'slug' => 'laravel-development',
'status' => 'active',
'service_category_id' => $category->id,
'description' => 'Backend'
]);
Service::create([
'title' => 'Orphaned laravel service',
'slug' => 'orphan',
'service_category_id' => null,
'description' => 'no category'
]);
$this->get('/uk/service-search?search=laravel')
->assertOk()
->assertSee('Laravel development')
->assertDontSee('Orphaned laravel service');
}
Маршрут — /uk/service-search із параметром запиту search. Це не /en/services/search. Записи використовують Service::create(); цей приклад не вигадує фабрику, якої модель не надає. Ці деталі визначають, чи може читач відтворити поведінку в цьому репозиторії.
Контролер застосовує і умову активного статусу, і whereHas('serviceCategory'). Цей тест перевіряє конкретний відрендерений результат за його фікстур. Щоб довести фільтрацію за категорією незалежно від усіх інших умов, додаткова фікстура має явно позначити сирітський рядок активним. Окремі тести мають покривати порожній запит, відсутність збігів і локалізований контент. Один приклад, що проходить, не можна описувати як повне покриття пошуку.
Тримайте ізоляцію тестів окремо від даних застосунку
RefreshDatabase може скинути схему в розв'язаній тестовій базі даних. Не запускайте приклад проти заповненої локальної бази застосунку чи production-бази. Спочатку перевірте ефективне середовище, з'єднання, hostname і назву бази; закешована конфігурація Laravel може підірвати припущення про те, які змінні середовища використовуються.
DigiSpace використовує специфічну для MySQL поведінку в інших місцях своїх запитів публічного сайту, тому заміна MySQL на SQLite лише для спрощення запуску може приховати проблеми сумісності. Використовуйте виділену тестову базу MySQL для suite репозиторію, що залежить від бази даних, із підставами зовнішніх інтеграцій за потреби. Будь-яке скидання чи очищення має бути обмежене перевіреною тестовою ціллю.
Коли ці передумови виконані, ціллю сфокусованого suite є tests/Feature/HeaderSearchTest.php. Очікуваний результат — не лише HTTP 200: відповідний заголовок каталогу з'являється, а сирітський — ні. Невдале твердження має вести назад до маршрутизації, фікстур чи умов запиту, а не до негайного послаблення тесту.
Відділяйте зміни коду від редакційних даних
Репозиторій може містити сід-контент без володіння кожним поточним значенням бази даних. Сідери DigiSpace на основі JSON для чистої інсталяції вставляють рядки, тоді як StructureTranslationsSeeder зіставляє наявні записи та заповнює відсутні переклади. Наявні непорожні редакційні переклади виграють. Жоден механізм не є універсальним публікатором для переглянутої статті.
Ця відмінність пояснює, чому деплой оновленого JSON-файлу може залишити живу сторінку незмінною. І навпаки, повторне прогінання сідерів чистої інсталяції в заповнену базу може зазнати невдачі чи вплинути на непов'язаний стан. Цільова зміна контенту має ідентифікувати записи за стабільним slug, обмежувати поля, які змінює, зберігати авторів і зображення, якщо вони не в обсязі, та робити відновлюваний знімок заздалегідь.
Для модернізації те саме правило застосовується до міграцій: знайте, якими даними володіє зміна. Уникайте поєднання оновлення runtime, редизайну схеми та широкої заміни контенту в одному релізі. Коли результат неправильний, менші зміни дають змогу ідентифікувати, яка операція внесла відмінність.
Перевіряйте результати деплою, а не лише результати збірки
Хук деплою DigiSpace запускає міграції, публікує ресурси Livewire, перебудовує кеші конфігурації та представлень і генерує sitemap. Це конкретна поведінка репозиторію. Це не доказ того, що кожну міграцію можна скасувати, або що відновлення попередньої директорії коду відновлює також вміст бази даних.
Визначте відкат коду та відновлення даних окремо. Попередній реліз може більше не розуміти змінену схему. Відновлення бази може відкинути правки, зроблені після бекапу. Для еволюції схеми надавайте перевагу сумісним етапним змінам, коли це можливо; для контенту — зберігайте знімок на рівні полів і перевіряйте втручальні правки перед його відновленням.
Публічні ресурси потребують незалежної перевірки. Коректний тег og:image все ще може вказувати на відсутній файл. Перевіряйте HTTP-результат, тип контенту, розміри зображення та видиме зображення замість трактування твердження метаданих як повного тесту соціального перегляду. Для локалізованих сторінок інспектуйте також canonical-посилання та фактичні цілі навігації поруч із перекладеними заголовками.
Що це доводить і коли це не копіювати
Репозиторій дає доказ цільового тесту пошуку, явних обмежень публічних запитів та окремих механізмів деплою і перекладів. Він не надає виміряного зменшення інцидентів чи вартості розробки до і після. Захищувана вигода вужча: важливу поведінку можна назвати й перевірити замість повторного відкриття вручну після кожної зміни.
Не перетворюйте інкрементальну модернізацію на нескінченні латки, коли підлягаючий продукт замінюється. Не вводьте шар сервісів навколо кожної короткої функції без конкретної межі для захисту. І не починайте широке оновлення, коли бекапи, видимість runtime та ізольоване середовище перевірки ще відсутні.
Для обмеженої співпраці дивіться розробку та модернізацію PHP. Починайте з одного workflow, його очікуваного результату та умов збою. Це створює корисний перший реліз і кращу основу для вирішення, чи наступний крок — супровід, вилучення чи заміна.