# Обектно-ориентирано програмиране в PHP

> ООП в PHP: класове, интерфейси, trait и enum, нови езикови средства от PHP 8.0 до 8.4 и връзката с десериализацията и сигурността на приложенията.

Източник: https://phpsos.de/bg/php/objektorientierung/  
Актуалност: 25.10.2026  
Доставчик: PHP SOS, Спешна помощ за PHP и сигурност на сървъри. Незабавна помощ по WhatsApp: https://wa.me/491736494914?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B9%D1%82%D0%B5%2C%20PHP%20SOS%2C%20%D0%B8%D0%BC%D0%B0%D0%BC%D0%B5%20%D0%BD%D1%83%D0%B6%D0%B4%D0%B0%20%D0%BE%D1%82%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%20%D1%81%20%D0%BD%D0%B0%D1%88%D0%B8%D1%8F%20PHP%20%D1%81%D1%8A%D1%80%D0%B2%D1%8A%D1%80.%20%D0%A4%D0%B8%D1%80%D0%BC%D0%B0%3A%20%E2%80%A6%20%D0%A3%D0%B5%D0%B1%D1%81%D0%B0%D0%B9%D1%82%3A%20%E2%80%A6

**Накратко:** Обектно-ориентираното програмиране (ООП) обединява данните и принадлежащите им функции в класове. За целта PHP предлага класове, абстрактни класове, интерфейси, trait и от PHP 8.1 enum. С PHP 8.0 до 8.4 бяха добавени много езикови средства, например constructor promotion, `readonly`, property hooks и асиметрична видимост. Важно за сигурността: добре капсулираният код се проверява по-лесно, а магическите методи правят несигурната десериализация опасна. Срещу уязвимости в интерпретатора като PHP2Shell ООП не помага.

## Какво означава обектно-ориентирано програмиране в PHP

Вместо да се използват разпръснати функции и глобални променливи, един клас описва нещо от предметната област: поръчка, клиент, фактура. Той определя какви данни принадлежат към него (свойства) и какво може да се прави с тях (методи). Обектът е конкретен екземпляр на този клас.

За вземащите решения това има практическа стойност: обектно-ориентираният код с ясни класове се тества, проверява и предава на изпълнители по-добре. Старите PHP приложения от много отделни скриптове с глобални променливи, напротив, се поддържат трудно и са податливи на грешки при надграждане.

Централна идея е капсулирането: един клас показва навън само методите, от които другите наистина се нуждаят, и защитава вътрешното си състояние. Една поръчка тогава може да бъде отбелязана като платена например само чрез метод, който предварително проверява дали това изобщо е допустимо. Събирането на такива правила на едно място е печалба и за сигурността.

## Градивните елементи накратко

| Елемент | Предназначение | Кратък пример |
|---|---|---|
| Клас | чертеж за обекти със свойства и методи | `class Rechnung { ... }` |
| абстрактен клас | обща основа, не може да се инстанцира директно | `abstract class Zahlart { ... }` |
| Интерфейс | договор: кои методи трябва да предоставя един клас | `interface Versandfaehig { ... }` |
| Trait | методи за повторна употреба в класове без общ родителски клас | `trait MitZeitstempel { ... }` |
| Enum | фиксиран набор от допустими стойности като самостоятелен тип, от PHP 8.1 | `enum Status { case Offen; ... }` |

Видимостите (`public`, `protected`, `private`) определят кой може да достъпва свойствата и методите. Класовете се организират в пространства от имена (namespaces) и се зареждат чрез autoloader; как работи това, показва страницата [Пространства от имена и autoloading](https://phpsos.de/bg/php/namespaces-autoloading/).

## Съвременният PHP: новостите от 8.0 до 8.4

Следните езикови средства са документирани в ръководството на PHP, респективно в съобщенията за изданията:

| Версия | Новост |
|---|---|
| 8.0 | Constructor promotion, nullsafe оператор `?->`, `::class` върху обекти |
| 8.1 | `readonly` свойства, enum, `new` в инициализатори, `final` за константи на клас |
| 8.2 | `readonly` класове; динамичните свойства се считат за остарели |
| 8.3 | Атрибут `#[\Override]`, типизирани константи на клас |
| 8.4 | Property hooks, асиметрична видимост, `new` без заобикалящи скоби |

Пример, който комбинира няколко от тези средства:

```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,  // от 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 вместо грешка
```

`readonly` пречи идентификаторът да бъде променян след създаването. `private(set)` позволява четене отвън, но запис само в рамките на класа. Такива гаранции в кода правят по-малко вероятни грешките, които иначе проличават едва в експлоатация. Типовете зад това обяснява страницата [Типовата система на PHP](https://phpsos.de/bg/php/typsystem/).

### Клопки при надграждане в обектно-ориентирания код

За по-старите приложения две промени са особено важни. От PHP 8.2.0 създаването на динамични свойства е остаряло, т.е. на свойства, които не са декларирани в класа, освен ако класът не носи атрибута `#[\AllowDynamicProperties]`. По-старият код често ги използва неосъзнато и тогава логовете се пълнят със забележки. Освен това типизираните свойства според ръководството трябва да са инициализирани преди първото четене, иначе PHP хвърля `Error`.

Полезен е атрибутът `#[\Override]` от PHP 8.3: той отбелязва метод като презаписване на метод на родителя. Ако този метод вече не съществува, например след преименуване в библиотека, PHP съобщава грешка, вместо методът тихо да остане без ефект. Такива проверки правят надграждането по-предвидимо; при закъсали стари проекти ни подпомага нашата [миграция към поддържана версия на PHP](https://phpsos.de/bg/leistungen/php-migration-legacy/).

## Обекти и памет

Обектите в PHP се предават чрез идентификатори (handles). Ако един обект се подаде на функция, тя работи със същия обект, а не с копие. Това е ефективно, но лесно води до циклични препратки, например когато поръчката познава своите позиции, а всяка позиция – отново своята поръчка. Такива цикли броенето на препратките само не почиства; за това PHP има собствен garbage collector. Подробности има на страницата [Управление на паметта в PHP](https://phpsos.de/bg/php/speicherverwaltung/).

## ООП и сигурност: магически методи и десериализация

PHP познава магически методи, които се извикват автоматично, например `__construct`, `__destruct`, `__toString`, `__get` или `__wakeup`. Това е удобно, но има и обратна страна: когато приложение превръща чужди данни с `unserialize()` обратно в обекти, атакуващият може да определи кои класове да възникнат и така да задейства наличен код в магически методи. Как това се предотвратява, описва наръчникът [Несигурна десериализация в PHP](https://phpsos.de/bg/ratgeber/deserialisierung-php/). Накратко: за обмен на данни използвайте `json_encode()` и `json_decode()`, а `unserialize()` само за собствени, достоверни данни, в идеалния случай с опцията `allowed_classes`.

При PHP2Shell добре написаният обектно-ориентиран код, напротив, не помага. CVE-2026-109618 и CVE-2026-109619 се намират в интерпретатора, а при mod_php според екипа на PHP е показан експлойт, преди да се изпълни кодът на приложението. Задължителни са актуализацията до PHP 8.5.12, 8.4.27, 8.3.36 или 8.2.35 и рестартирането на всички PHP процеси.

## Как помага PHP SOS конкретно?

- Оценяваме структурата на Вашето приложение и показваме кои части затрудняват надграждането до поддържана версия на PHP.
- Търсим целенасочено рискови шаблони като `unserialize()` върху чужди данни и опасни магически методи.
- Проверяваме собствените разработки в рамките на [одит на сигурността и тест за проникване](https://phpsos.de/bg/leistungen/sicherheitsaudit-penetrationstest/).
- Внедряваме актуализацията на PHP, рестартираме всички worker процеси и след това тестваме приложението.


## Често задавани въпроси

**PHP обектно-ориентиран език ли е?**  
PHP поддържа както процедурен, така и обектно-ориентиран код. Фреймуърците, ядрата на CMS и магазинните системи днес обаче са изградени предимно обектно-ориентирано, с класове, интерфейси и пространства от имена.

**Каква е разликата между интерфейс и абстрактен клас?**  
Интерфейсът описва само кои методи трябва да предоставя един клас. Абстрактният клас може допълнително да съдържа вече код и свойства, но не може да се инстанцира директно. Един клас може да има няколко интерфейса, но само един родителски клас.

**Откога има enum в PHP?**  
Изброените типове (enumerations) се появиха с PHP 8.1. Те заменят набори от константи със самостоятелен тип, който допуска само дефинираните случаи. Backed enum имат допълнително стойност от тип int или string.

**Защо магическите методи са важни за сигурността?**  
Методи като __destruct или __wakeup PHP извиква автоматично, например при десериализиране на данни. Ако чужди данни попаднат непроверени в unserialize(), това може да задейства неочаквани процеси в наличните класове.

## Източници

- [Ръководство на PHP: Класове и обекти, основи](https://www.php.net/manual/de/language.oop5.basic.php)
- [Ръководство на PHP: Свойства](https://www.php.net/manual/en/language.oop5.properties.php)
- [Ръководство на PHP: Видимост](https://www.php.net/manual/en/language.oop5.visibility.php)
- [PHP 8.1 Release](https://www.php.net/releases/8.1/en.php)
