# Programowanie obiektowe w PHP

> Programowanie obiektowe w PHP: klasy, interfejsy, traity i enumy, nowe środki językowe od PHP 8.0 do 8.4 oraz związek z deserializacją i bezpieczeństwem.

Źródło: https://phpsos.de/pl/php/objektorientierung/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**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](https://phpsos.de/pl/php/namespaces-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
<?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](https://phpsos.de/pl/php/typsystem/).

### 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](https://phpsos.de/pl/leistungen/php-migration-legacy/).

## 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](https://phpsos.de/pl/php/speicherverwaltung/).

## 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](https://phpsos.de/pl/ratgeber/deserialisierung-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](https://phpsos.de/pl/leistungen/sicherheitsaudit-penetrationstest/).
- 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.

## Źródła

- [Podręcznik PHP: klasy i obiekty, podstawy](https://www.php.net/manual/de/language.oop5.basic.php)
- [Podręcznik PHP: właściwości](https://www.php.net/manual/en/language.oop5.properties.php)
- [Podręcznik PHP: widoczność](https://www.php.net/manual/en/language.oop5.visibility.php)
- [Wydanie PHP 8.1](https://www.php.net/releases/8.1/en.php)
