Krótko: Programowanie obiektowe (OOP) łączy dane i należące do nich funkcje w klasach. PHP oferuje w tym celu klasy, klasy abstrakcyjne, interfejsy, traity, a od PHP 8.1 enumy. W PHP 8.0 do 8.4 doszło wiele środków językowych, na przykład promocja konstruktora, readonly, property hooks i asymetryczna widoczność. Dla bezpieczeństwa ważne jest to, że dobrze zamknięty w kapsułę kod łatwiej sprawdzić, a metody magiczne czynią niebezpieczną niebezpieczną deserializację. Przed lukami w interpreterze, takimi jak PHP2Shell, OOP nie chroni.
Co oznacza programowanie obiektowe w PHP
Zamiast luźnych funkcji i zmiennych globalnych klasa opisuje rzecz ze świata biznesu: zamówienie, klienta, fakturę. Określa, jakie dane do niej należą (właściwości) i co można z nimi robić (metody). Obiekt jest konkretnym egzemplarzem tej klasy.
Dla osób podejmujących decyzje ma to wartość praktyczną: kod obiektowy z jasnymi klasami łatwiej testować, sprawdzać i przekazywać usługodawcom. Stare aplikacje PHP złożone z wielu pojedynczych skryptów ze zmiennymi globalnymi są natomiast trudne w utrzymaniu i podatne na błędy przy aktualizacjach.
Centralną ideą jest enkapsulacja: klasa udostępnia na zewnątrz tylko te metody, których inni naprawdę potrzebują, i chroni swój wewnętrzny stan. Zamówienie można wtedy na przykład oznaczyć jako opłacone tylko metodą, która wcześniej sprawdza, czy jest to w ogóle dopuszczalne. Zebranie takich reguł w jednym miejscu jest zyskiem także dla bezpieczeństwa.
Elementy składowe w skrócie
| Element | Cel | Krótki przykład |
|---|---|---|
| Klasa | wzorzec obiektów z właściwościami i metodami | class Rechnung { ... } |
| klasa abstrakcyjna | wspólna baza, nie do bezpośredniego instancjonowania | abstract class Zahlart { ... } |
| Interfejs | umowa: jakie metody klasa musi oferować | interface Versandfaehig { ... } |
| Trait | metody do ponownego użycia w klasach bez wspólnej klasy nadrzędnej | trait MitZeitstempel { ... } |
| Enum | stały zestaw dozwolonych wartości jako własny typ, od PHP 8.1 | enum Status { case Offen; ... } |
Widoczności (public, protected, private) regulują, kto może uzyskiwać dostęp do właściwości i metod. Klasy są organizowane w przestrzeniach nazw i ładowane przez autoloader; jak to działa, pokazuje strona Przestrzenie nazw i autoloading.
Nowoczesny PHP: nowości od 8.0 do 8.4
Poniższe środki językowe są udokumentowane w podręczniku PHP lub w ogłoszeniach o wydaniach:
| Wersja | Nowość |
|---|---|
| 8.0 | promocja konstruktora, operator nullsafe ?->, ::class na obiektach |
| 8.1 | właściwości readonly, enumy, new w inicjalizatorach, final dla stałych klas |
| 8.2 | klasy readonly; właściwości dynamiczne uznano za przestarzałe |
| 8.3 | atrybut #[\Override], typowane stałe klas |
| 8.4 | property hooks, asymetryczna widoczność, new bez otaczających nawiasów |
Przykład łączący kilka z tych środków:
<?php
declare(strict_types=1);
enum Status: string
{
case Offen = 'offen';
case Bezahlt = 'bezahlt';
}
final class Bestellung
{
public function __construct(
public readonly int $id,
public private(set) Status $status = Status::Offen, // od PHP 8.4
) {}
public function alsBezahltMarkieren(): void
{
$this->status = Status::Bezahlt;
}
}
$b = new Bestellung(42);
$b->alsBezahltMarkieren();
echo $b->status->value; // bezahlt
$s = Status::tryFrom('storniert'); // null zamiast błędu
readonly uniemożliwia zmianę identyfikatora po utworzeniu. private(set) pozwala na odczyt z zewnątrz, ale na zapis tylko wewnątrz klasy. Takie zapewnienia w kodzie zmniejszają prawdopodobieństwo błędów, które inaczej wychodzą na jaw dopiero w eksploatacji. Typy, które za tym stoją, wyjaśnia strona System typów w PHP.
Pułapki aktualizacji w kodzie obiektowym
W starszych aplikacjach szczególnie istotne są dwie zmiany. Od PHP 8.2.0 tworzenie właściwości dynamicznych, czyli takich, które nie są zadeklarowane w klasie, jest przestarzałe, chyba że klasa ma atrybut #[\AllowDynamicProperties]. Starszy kod często robi to nieświadomie i wtedy wypełnia logi uwagami. Poza tym według podręcznika typowane właściwości muszą być zainicjalizowane przed pierwszym odczytem, w przeciwnym razie PHP zgłasza Error.
Pomocny jest atrybut #[\Override] z PHP 8.3: oznacza metodę jako nadpisanie metody klasy nadrzędnej. Jeśli takiej metody już nie ma, na przykład po zmianie nazwy w bibliotece, PHP zgłasza błąd, zamiast pozwolić metodzie po cichu działać w próżnię. Takie kontrole czynią aktualizacje bardziej przewidywalnymi; w utkniętych starych projektach pomaga nasza migracja do wspieranej wersji PHP.
Obiekty i pamięć
Obiekty są w PHP przekazywane przez identyfikatory (handle). Jeśli przekaże się obiekt do funkcji, pracuje ona na tym samym obiekcie, a nie na kopii. Jest to wydajne, ale łatwo prowadzi do odwołań cyklicznych, na przykład gdy zamówienie zna swoje pozycje, a każda pozycja znowu swoje zamówienie. Takich cykli samo zliczanie referencji nie sprząta; PHP ma do tego własny garbage collector. Szczegóły są na stronie Zarządzanie pamięcią w PHP.
OOP a bezpieczeństwo: metody magiczne i deserializacja
PHP zna metody magiczne, wywoływane automatycznie, na przykład __construct, __destruct, __toString, __get lub __wakeup. Jest to praktyczne, ale ma ciemną stronę: jeśli aplikacja zamienia obce dane za pomocą unserialize() z powrotem w obiekty, atakujący może zdecydować, jakie klasy powstaną, i w ten sposób uruchomić istniejący kod w metodach magicznych. Jak temu zapobiec, opisuje poradnik Niebezpieczna deserializacja w PHP. Krótko: do wymiany danych używać json_encode() i json_decode(), a unserialize() stosować tylko dla własnych, zaufanych danych, najlepiej z opcją allowed_classes.
Przy PHP2Shell dobry kod obiektowy natomiast nie pomaga. CVE-2026-109618 i CVE-2026-109619 leżą w interpreterze, a przy mod_php zespół PHP pokazał exploit, zanim zacznie działać kod aplikacji. Obowiązkowa jest aktualizacja do PHP 8.5.12, 8.4.27, 8.3.36 lub 8.2.35 i restart wszystkich procesów PHP.
Jak konkretnie pomaga PHP SOS?
- Oceniamy budowę Państwa aplikacji i pokazujemy, które jej części utrudniają przejście na wspieraną wersję PHP.
- Szukamy celowo ryzykownych wzorców, takich jak
unserialize()na obcych danych i niebezpieczne metody magiczne. - Sprawdzamy własne rozwiązania w ramach audytu bezpieczeństwa i testu penetracyjnego.
- Instalujemy aktualizację PHP, restartujemy wszystkie workery i potem testujemy aplikację.
Częste pytania
Czy PHP jest językiem obiektowym?
PHP obsługuje zarówno kod proceduralny, jak i obiektowy. Frameworki, rdzenie CMS i systemy sklepowe są dziś jednak w przeważającej mierze zbudowane obiektowo, z klasami, interfejsami i przestrzeniami nazw.
Jaka jest różnica między interfejsem a klasą abstrakcyjną?
Interfejs opisuje tylko, jakie metody klasa musi oferować. Klasa abstrakcyjna może dodatkowo zawierać już kod i właściwości, ale nie można jej bezpośrednio instancjonować. Klasa może mieć wiele interfejsów, ale tylko jedną klasę nadrzędną.
Od kiedy w PHP istnieją enumy?
Enumeracje pojawiły się w PHP 8.1. Zastępują zbiory stałych własnym typem, który dopuszcza tylko zdefiniowane przypadki. Backed enumy mają dodatkowo wartość int lub string.
Dlaczego metody magiczne mają znaczenie dla bezpieczeństwa?
Metody takie jak __destruct lub __wakeup PHP wywołuje automatycznie, na przykład przy deserializacji danych. Jeśli obce dane trafią bez sprawdzenia do unserialize(), może to wywołać nieoczekiwane przebiegi w istniejących klasach.