Skip to content
Udgivet
Opdateret

PHP-udvikling og modernisering af ældre systemer

Det meste PHP-arbejde, jeg bliver bedt om, handler om et system, der allerede tjener penge: en WordPress-hjemmeside, et Laravel-projekt, et specialudviklet bookingforløb, en betalingsintegration eller et adminværktøj, som medarbejderne bruger hver dag. Opgaven er at rette, udvide eller opgradere det uden at ødelægge det, virksomheden er afhængig af.

Den situation kender jeg indefra. Jeg byggede og vedligeholdt PHP-bookingmotoren bag Thailand-villas.com fra 2001, til platformen blev solgt i 2022, og fra 2011 også PHP-systemet bag klik.villas, et administrationssystem til udlejning af villaer. Begge var i drift, mens PHP, søgemaskiner, bookingkanaler og kundernes forventninger ændrede sig omkring dem. Det er baggrunden for rådene nedenfor.

Arbejdsgang for PHP-udvikling med backendmoduler, databasetjek, API-forbindelser og status for…

Én kodebase gennem to årtier med PHP

Bookingmotoren bag Thailand-villas.com begyndte på PHP 4 og var skrevet, som det meste PHP blev skrevet dengang: procedurale scripts, der delte kode via includes. Der fandtes ingen Composer, intet framework, som de fleste udviklere greb efter, og den objektmodel, PHP 5 kom med i 2004, fandtes endnu ikke.

Den stil var hurtig at bygge med og nem at sætte i drift, og platformen kørte på den i årevis. Det svære kom senere, da sproget udviklede sig, og koden skulle følge med, mens reservationerne blev ved med at komme ind.

Databaseadgangen er det tydeligste eksempel. Koden gik senere over til PDO, det databaselag, der har været en del af PHP siden version 5.1. Prepared statements med bundne parametre gav alle forespørgsler den samme, mere sikre måde at håndtere input på og én ensartet adgang til databasen. Det fjernede også en afhængighed, der ellers ville have blokeret opgraderinger: De gamle mysql_*-funktioner blev helt fjernet i PHP 7.0, så kode, der stadig brugte dem, slet ikke kunne køre på nyere versioner.

Sådan går det med det meste PHP, der lever længe. Sproget tvinger sjældent en omskrivning igennem, men hver generation udfaser noget, som ældre kode er afhængig af. Spørgsmålet for ejeren er, om den kode bliver udskiftet bevidst, ét område ad gangen, eller først bliver opdaget den dag, hostingudbyderen slukker for en gammel PHP-version. Sprogets egen historie finder du i PHP’s historie fra personlige værktøjer til et moderne sprog.

Efter at have ført min egen kode gennem de skift er det også det arbejde, jeg laver på andres PHP. Jeg finder den kode, der afhænger af funktioner, som den næste version fjerner eller ændrer, tilpasser den og tester de vigtige arbejdsgange på den nye version før skiftet, så en ny PHP-version ikke ender med at blokere forretningen. Hvordan jeg griber det an, står under en PHP-opgradering som et kontrolleret projekt.

Hvad et PHP-system med lang levetid lærer én

21 år med den samme kodebase giver nogle faste holdninger.

Kode, der virker, rummer viden, som ingen har skrevet ned. En ældre bookingmotor indeholder prisregler, særtilfælde i tilgængeligheden og genveje i administrationen, som findes, fordi nogen engang havde brug for dem. Skriver man systemet om fra bunden, skal alt det findes igen, som regel i produktion.

Forbedringer skal komme i små bidder. At holde Thailand-villas.com kørende i to årtier krævede løbende forbedringer, der bevarede de arbejdsgange, som fungerede, mens teknologien under dem ændrede sig.

Integrationer ændrer sig mere end ens egen kode. Kanalintegrationerne i klik.villas til Booking.com, Agoda og Rentals United skulle håndtere dataformater og regler for tilgængelighed, der blev ændret i den anden ende. Robust håndtering ved de grænser betød mere end elegance i kernen.

Den rigtige struktur afhænger af tiden. De stedspecifikke domæner, der passede til Thailand-villas.com i 2000’erne, ville være et tvivlsomt valg i dag. Beslutninger skal tages op igen, når omgivelserne ændrer sig, ikke kopieres fra det, der virkede før.

Typiske PHP-opgaver

  • Fejlrettelser i eksisterende PHP-kode
  • Forbedringer af WordPress-temaer, plugins og redaktørens arbejdsgange
  • Vedligeholdelse af Laravel-applikationer
  • Sikker opgradering af PHP-versioner uden sikkerhedsopdateringer
  • Integration med booking, CRM, betaling eller mail
  • Bedre performance i PHP, MySQL, caching eller frontend-output
  • Stabilisering af skrøbelig kode, før den bliver dyr at ændre
  • Nye funktioner uden at bygge hele systemet om

Rangér risiciene, før noget ændres

En applikations alder siger ikke meget i sig selv. Det afgørende er, hvad der gør den vanskelig eller farlig at vedligeholde:

  • En PHP-version uden sikkerhedsopdateringer eller forladte afhængigheder
  • Intet pålideligt udviklings- eller testmiljø
  • Manuel udrulning uden en afprøvet plan for at rulle tilbage
  • Vigtige arbejdsgange uden automatiske tests
  • Databaseændringer foretaget direkte i produktion
  • Forretningslogik blandet ind i skabeloner og kode, der håndterer forespørgsler
  • Integrationer uden logs, gentagne forsøg eller tydeligt ejerskab
  • Sikkerhedsantagelser, der ikke længere passer til den faktiske brug
  • Viden, der kun findes hos én person eller i selve koden

Rangér dem efter betydningen for driften. En PHP-version uden sikkerhedsopdateringer på et offentligt system haster mere end inkonsistente navne. En skrøbelig betalings- eller bookingintegration bør komme før en bred oprydning i kodestilen.

Ældre PHP-kode der moderniseres trinvis gennem tests og kontrollerede ændringer

Kortlæg systemet, før det ændres

Lav en oversigt over applikationen:

  • Indgange, routes, planlagte jobs og kommandolinjeopgaver
  • Databaser, tabeller, filer og ekstern lagring
  • Login, rettigheder og administrationsværktøjer
  • API’er, webhooks, mail, betaling og tredjepartsintegrationer
  • Hosting, udrulning, køer og baggrundsprocesser
  • Kritiske arbejdsgange for kunder og medarbejdere
  • Afhængigheder og deres versionskrav

Gå ikke ud fra, at kode kan fjernes, blot fordi den ser ubrugt ud. Et etableret system kan indeholde månedlige jobs, sjældne administrationshandlinger eller partnerintegrationer, som aldrig viser sig ved almindelig brug. Logs, serveropsætning, databaseaktivitet og samtaler med de personer, der bruger systemet, bekræfter, hvad der faktisk kører.

Gør adfærden synlig før refaktorering

Modernisering er sikrere, når ændringer kan følges i driften. Før en bred refaktorering bør der være ordentlig fejllogning, overblik over planlagte jobs og køer, overvågning af vigtige endpoints, alarmer ved gentagne fejl, kontrol af sikkerhedskopier og historik over udrulninger.

Logs må ikke afsløre adgangsoplysninger, persondata eller andre følsomme oplysninger. De skal vise, hvad der fejlede, hvor, og hvilken forretningshandling der blev ramt. Bedre indsigt i driften afslører også eksisterende fejl, som ellers let bliver tilskrevet nyt arbejde.

En ældre applikation er måske ikke bygget til automatiske tests, men test behøver ikke vente på en omskrivning. Begynd med tests, der fastholder den adfærd, som allerede er i brug:

  • Login og rettighedskontrol
  • Priser og beregninger
  • Oprettelse af ordrer, reservationer og henvendelser
  • Import, eksport og planlagte jobs
  • API- og webhookadfærd
  • Kritiske rapporter

Tests ved HTTP-, kommando-, service- eller databasegrænser giver nyttig beskyttelse, selv når den interne kode er tæt koblet. En høj dækningsprocent betyder langt mindre end at vide, at de arbejdsgange, folk er afhængige af, stadig opfører sig ens.

Behandl en PHP-opgradering som et kontrolleret projekt

En versionsvælger hos hostingudbyderen får selve skiftet til at se enkelt ud. Det er forberedelsen, der gør det sikkert. WordPress-plugins, specialudviklede temaer, Laravel-kode, Composer-pakker, cronjobs, serverudvidelser og betalings- eller bookingintegrationer kan alle afhænge af PHP’s adfærd.

PHP-opgradering forberedt med kompatibilitetstjek, staging, sikkerhedskopier, test og kontrolleret…

Notér den nuværende PHP-version og de installerede udvidelser, før noget ændres, og kortlæg derefter alt, der kører på PHP. Tjek den aktuelle livscyklus på PHP’s officielle side med understøttede versioner i stedet for at stole på en gammel projektnote.

En kontrolleret opgradering følger normalt denne rækkefølge:

  1. Gennemgå kompatibiliteten for applikation, plugins, tema og afhængigheder.
  2. Tag aktuelle sikkerhedskopier, og kontrollér hvordan de gendannes.
  3. Genskab systemet i et testmiljø eller en repræsentativ kopi.
  4. Slå streng fejlrapportering til i det kontrollerede miljø.
  5. Ret udfasede funktioner, inkompatibel adfærd og biblioteker uden support.
  6. Test repræsentative arbejdsgange på den nye PHP-version.
  7. Udrul med overvågning og en plan for at rulle tilbage eller rette fremad.
  8. Test de kritiske arbejdsgange igen efter skiftet i produktion.

Test først de forløb, der skaber omsætning eller henvendelser: formularer, checkout, booking, login, redigering, søgning, API-callbacks og specialudviklede rapporter.

Hold opgraderingen adskilt fra andre arkitekturændringer. En fokuseret opgradering gør kompatibilitetsproblemer lettere at finde og begrænser, hvor meget adfærd der ændres på én gang.

Få styr på afhængighederne

Nogle ældre PHP-applikationer indeholder kopierede biblioteker, manuelt ændret vendor-kode eller afhængigheder, som ingen har kigget på i årevis.

Lav en tydelig oversigt over afhængighederne. Flyt de pakker, det giver mening at styre, over i Composer, fjern kun pakker, når det er bekræftet, at de ikke bruges, og find de forladte biblioteker, der skal erstattes eller isoleres. Opdatér i kontrollerede grupper, læs opgraderingsnoterne, gennemgå indirekte afhængigheder, og test den adfærd, der bruger hver pakke.

Ret ikke i installerede vendor-filer for at få en opdatering igennem. Rettelsen forsvinder ved næste installation, og det egentlige kompatibilitetsproblem består. Kan en afhængighed ikke erstattes med det samme, så isolér den bag en tydelig grænse, så mindre af applikationen afhænger direkte af den.

Skab grænser omkring vanskelig kode

Ældre kode bliver lettere at modernisere, når ny og ændret adfærd holdes ude af de mest sammenfiltrede områder. Nyttige grænser kan være:

  • En service omkring et eksternt API
  • En separat komponent omkring kompleks databaseadgang
  • En dedikeret klasse til priser eller validering
  • En adapter omkring et gammelt bibliotek
  • Et job i en kø omkring langsomt eksternt arbejde
  • Et nyt endpoint eller modul ved siden af en ældre implementering

Hver grænse giver en vigtig del af adfærden ét forståeligt sted og mindsker antallet af filer, der skal ændres sammen. Moderne designmønstre er kun nyttige, hvor de gør netop det.

Ændr databasen og udrulningen forsigtigt

Gamle og nye versioner af applikationen kan kortvarigt køre mod samme databasestruktur under en udrulning, så databaseændringer er risikable. Foretræk bagudkompatible trin:

  1. Tilføj en ny kolonne eller tabel uden at fjerne den gamle struktur.
  2. Udrul kode, der kan fungere under overgangen.
  3. Migrér eller udfyld data i kontrollerede portioner.
  4. Bekræft, at den nye vej er stabil.
  5. Fjern først gammel kode og databasestruktur, når intet bruger dem.

Store datamigreringer bør kunne overvåges og genoptages og skal testes med realistiske datamængder. En migrering, der lykkes på en lille udviklingsdatabase, kan låse tabeller eller overskride tidsgrænser i produktion. En sikkerhedskopi beskytter kun, når gendannelsen er afprøvet, og man ved, hvor lang tid den tager.

Udgivelsesprocessen skal også kunne gentages: versionsstyrede ændringer, ensartet installation af afhængigheder, automatiske kontroller, opsætning pr. miljø, registrerede databasemigreringer, udrulningslogs, driftstjek og en afprøvet plan for genopretning. Mindre udgivelser sænker risikoen og gør det lettere at koble en fejl til en bestemt ændring.

Refaktorér, hvor der alligevel arbejdes

Brede oprydningsprojekter bruger ofte tid uden at forbedre de dele af systemet, der betyder noget. Refaktorér, når der er en konkret grund: en fejl afslører uklart ansvar, en ny funktion ville kopiere vanskelig kode, en afhængighed skal isoleres, en langsom operation har brug for en tydeligere grænse, eller et sikkerhedsproblem kræver en mere robust løsning.

Nogle områder er bedre at erstatte end at reparere. En afgrænset omskrivning giver mening, når modulet har et tydeligt interface, den eksisterende adfærd kan testes, erstatningen løser et konkret problem, datamigrering og tilbagerulning kan håndteres, og gammel og ny løsning kan sammenlignes, før den gamle fjernes.

En importproces, et rapportmodul, en søgefunktion, en administrationsside eller en isoleret integration kan passe til den beskrivelse. At erstatte ét afgrænset modul er noget helt andet end at bygge hele applikationen om. Artiklen om at forbedre en eksisterende hjemmeside uden at bygge den om går mere i dybden med det valg.

WordPress, Laravel og specialudviklet PHP

WordPress-arbejde handler ofte om plugins, temaer, performance, databaseoprydning, formularer, søgning, checkout eller redaktørens arbejdsgange. Specialudvikling og rettelser i WordPress dækker det direkte.

Laravel-arbejde handler typisk om routes, køer, planlagte opgaver, API’er, login, datamodeller og udrulning. Se udvikling og vedligeholdelse i Laravel.

Specialudviklet PHP kan være ældre kode uden et egentligt framework. Det gør ikke automatisk systemet til en kandidat til udskiftning. Ofte er det mere kontrolleret at stabilisere de risikable områder, beskytte vigtige arbejdsgange med tests, opgradere PHP og forbedre koden gradvist.

Når en forespørgsel er langsom, så mål, hvor tiden bruges, før PHP får skylden: databaseforespørgsler, object cache og page cache, eksterne API’er, billeder, JavaScript og hosting er alle mulige årsager.

API’er og forretningens arbejdsgange

Mange PHP-systemer bliver forretningskritiske, fordi de forbinder bookingmotorer, kalendere, betalingsudbydere, CRM, mailtjenester, produktdata eller rapportering. klik.villas er et typisk eksempel: reservationer, lejeindtægter, udgifter, vedligeholdelse og eksterne bookingkanaler mødtes i én PHP-applikation.

Driftssikre API’er kræver gentagne forsøg, logning, idempotens, validering og klar fejlhåndtering. Et kald, der virker én gang under udvikling, er ikke nok. Guiden til driftssikre API-integrationer gennemgår mønstrene mere detaljeret.

En trinvis plan for modernisering

En praktisk plan begynder som regel med sikkerhed og slutter med strukturelle forbedringer:

  1. Kortlæg systemet, og rangér driftsrisiciene.
  2. Forbedr sikkerhedskopier, logs, overvågning og overblik over udrulninger.
  3. Beskyt kritiske arbejdsgange med tests.
  4. Flyt til en understøttet PHP-version.
  5. Få afhængighederne under kontrol.
  6. Isolér skrøbelige integrationer og forretningsregler.
  7. Refaktorér eller erstat afgrænsede områder, når konkret arbejde når dem.
  8. Mål, om driftssikkerhed, vedligeholdelse og levering bliver bedre.

Når planen er gennemført, kan applikationen stadig se gammel ud nogle steder. Men den er sikrere at drive, lettere at forstå og nemmere at ændre, og den værdifulde adfærd er der stadig. Hvis et eksisterende PHP-system har brug for den type arbejde, kan du sende mig en kort beskrivelse af systemet, den berørte arbejdsgang og den aktuelle risiko.

Flere artikler