# Kļūdas un izņēmumi (exceptions) PHP

> PHP kļūdas un izņēmumi (exceptions): Throwable, Error un Exception, try/catch/finally, globālie handler un droši iestatījumi kļūdu izvadei un žurnāliem.

Avots: https://phpsos.de/lv/php/fehler-und-exceptions/  
Aktuāls uz: 25.10.2026  
Pakalpojuma sniedzējs: PHP SOS, PHP ārkārtas palīdzība un serveru drošība. Tūlītēja palīdzība pa WhatsApp: https://wa.me/491736494914?text=Sveiki%2C%20PHP%20SOS%2C%20mums%20nepiecie%C5%A1ama%20pal%C4%ABdz%C4%ABba%20ar%20m%C5%ABsu%20PHP%20serveri.%20Uz%C5%86%C4%93mums%3A%20%E2%80%A6%20Vietne%3A%20%E2%80%A6

**Īsi:** PHP ziņo par problēmām divējādi: kā klasiskas kļūdas, piemēram, brīdinājumus un piezīmes, ko vada ar `error_reporting`, un kā izņēmumus, ko var noķert ar `try` un `catch`. Kopš PHP 7 daudzas iekšējās kļūdas met klases `Error` objektu; kopā ar `Exception` tas ievieš interfeisu `Throwable`. Produkcijā spēkā: kļūdas reģistrēt žurnālā, nekad nerādīt pārlūkprogrammā. PHP 8.5 gadījumā PHP2Shell dēļ pie pagaidu pasākumiem pieder arī `fatal_error_backtraces=0`.

## Divas pasaules: klasiskās kļūdas un izņēmumi

PHP nāk no laikiem, kad kļūdas galvenokārt tika izvadītas kā ziņojums: piezīmes (`E_NOTICE`), brīdinājumi (`E_WARNING`), novecojušas funkcijas (`E_DEPRECATED`) un fatālas kļūdas (`E_ERROR`). Daudzi no šiem ziņojumiem ļauj skriptam turpināt darbu, bieži ar nepareiziem vai tukšiem datiem.

Izņēmumi darbojas citādi. Tie pārtrauc ierasto norisi un pāriet uz nākamo piemērotu `catch` bloku. Ja tāda nav, skripts beidzas. Lēmumu pieņēmējiem atšķirība ir svarīga: kluss brīdinājums var novest pie tā, ka pasūtījums tiek saglabāts nepilnīgi, un neviens to nepamana. Izņēmums problēmu padara redzamu un apstrādājamu.

Par maz novērtēts klasisko ziņojumu ieguvums ir `E_DEPRECATED` tipa norādes. Tās paziņo, ka valodas līdzeklis nākamajā PHP versijā tiks atcelts. Kas tās vāc žurnālā un regulāri izvērtē, pirms jauninājuma zina, kuras vietas jāpielāgo, un steidzamas drošības ievainojamības gadījumā nav ilgi jātestē.

## Throwable hierarhija

Viss, ko var mest ar `throw` un noķert ar `catch`, ievieš `Throwable`. Zem tā ir divi zari:

| Klase | Nolūks | Apakšklašu piemēri |
|---|---|---|
| `Exception` | lietojumprogrammas un paplašinājumu gaidāmas kļūdas | `ErrorException`, `PDOException`, paša definētas klases |
| `Error` | PHP iekšējās kļūdas | `TypeError`, `ValueError`, `ArgumentCountError`, `ArithmeticError`, `DivisionByZeroError`, `UnhandledMatchError` |

Paša kļūdu klases mantojamas no `Exception`, nevis no `Error`. Kopš PHP 8.0 lielākā daļa iekšējo funkciju nederīgu parametru gadījumā met `TypeError` vai `ValueError`, nevis tikai izvada brīdinājumu. Viens šāds gadījums ir `strlen([])`.

## try, catch un finally praksē

```php
<?php
declare(strict_types=1);

final class ZahlungFehlgeschlagen extends RuntimeException {}

function bezahlen(Bestellung $b, Zahlungsdienst $dienst, LoggerInterface $log): bool
{
    try {
        $dienst->belasten($b->betrag(), $b->referenz());
        return true;
    } catch (ZahlungFehlgeschlagen $e) {
        $log->warning('Zahlung abgelehnt', ['bestellung' => $b->id(), 'exception' => $e]);
        return false;
    } catch (TimeoutException | VerbindungsFehler) {
        // kopš PHP 8.0 mainīgais catch ir neobligāts
        $log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
        return false;
    } finally {
        $dienst->verbindungSchliessen();
    }
}
```

Vairākas klases var apvienot vienā `catch` ar `|`. `finally` bloks darbojas vienmēr, neatkarīgi no tā, vai kļūda radusies. Kopš PHP 8.0 `throw` ir arī izteiksme, un to var likt, piemēram, aiz `??`: `$id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');`.

## Globālie handler: set_error_handler un set_exception_handler

Divas funkcijas noķer to, kas citādi izslīdētu. `set_exception_handler()` reģistrē funkciju nenoķertiem Throwable. Saskaņā ar rokasgrāmatu skripts pēc tās izsaukšanas beidzas; tāpēc tā der reģistrēšanai žurnālā un neitrālai kļūdas lapai, nevis darba turpināšanai.

Izrādījies noderīgs handler, kas pilnu kļūdu ar laiku un nejaušu identifikatoru ieraksta žurnālā, bet apmeklētājam rāda tikai neitrālu lapu ar šo identifikatoru. Atbalsts tad var atrast gadījumu žurnālā, un iekšējās detaļas netiek atklātas ārpusei.

`set_error_handler()` noķer klasiskās kļūdas. Rokasgrāmata rāda, kā tās pārveidot par `ErrorException`, lai brīdinājumus apstrādātu kā izņēmumus:

```php
<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
    if (!(error_reporting() & $nr)) {
        return false; // izslēgts ar error_reporting
    }
    if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
        return false; // norādes par novecojušo neeskalēt
    }
    throw new ErrorException($text, 0, $nr, $datei, $zeile);
});
```

Fatālas kļūdas, piemēram, atmiņas pārpildi, šādi noķert nevar. Kas pārpildes gadījumā notiek iekšienē, izskaidro lapa [memory_limit un Out-of-Memory](https://phpsos.de/lv/php/out-of-memory/).

## Kļūdu izvades un reģistrēšanas konfigurēšana

Svarīgākie iestatījumi ar noklusējuma vērtībām saskaņā ar rokasgrāmatu:

| Iestatījums | Noklusējums | Ieteikums produkcijai |
|---|---|---|
| `error_reporting` | `E_ALL` kopš PHP 8.0.0 | `E_ALL` |
| `display_errors` | `1` | `Off` |
| `display_startup_errors` | `1` kopš PHP 8.0.0 | `Off` |
| `log_errors` | `0` | `On` |
| `error_log` | tukšs (tīmekļa servera vai SAPI žurnāls) | atsevišķs fails ārpus webroot |
| `fatal_error_backtraces` | `1`, jauns PHP 8.5.0 | īslaicīgi `0` (PHP2Shell) |

Kopš PHP 8.2.0 `error_log_mode` nosaka žurnāla faila tiesības, pēc noklusējuma `0644`. Ja žurnālos ir personas dati vai ceļi, saprātīga ir stingrāka vērtība, lai citi servera lietotāji tos nevarētu lasīt. Ar `ignore_repeated_errors` var apvienot identiskus ziņojumus no tā paša faila un rindas, lai kļūdu cilpa nepārpildītu žurnālu.

Komplektā iekļautais `php.ini-production` `display_errors` jau iestata uz `Off`. Saskaņā ar rokasgrāmatu `ini_set('display_errors', ...)` izpildes laikā uz fatālām kļūdām neiedarbojas, un sintakses kļūdas rodas, pirms `ini_set()` vispār darbojas. Šīs vērtības tāpēc jāliek servera konfigurācijā. Fona informācija ir rakstā [Kļūdu izvades izslēgšana produkcijā](https://phpsos.de/lv/blog/display-errors-produktion/); par to, kā žurnālus vest bez datu noplūdes, rakstā [Droša reģistrēšana](https://phpsos.de/lv/blog/sicher-loggen-php/).

## Kļūdu apstrāde un PHP2Shell

PHP 8.5 gadījumā php.net kā vienu no pagaidu pasākumiem pret PHP2Shell min `fatal_error_backtraces=0` iestatīšanu un PHP pārstartēšanu pēc tam. Pārējie pasākumi attiecas uz `memory_limit`, `post_max_size` un `session.upload_progress.enabled`. Neviens no tiem neaizstāj atjauninājumu uz PHP 8.5.12, 8.4.27, 8.3.36 vai 8.2.35.

```ini
; tikai PHP 8.5, php.ini vai FPM pūlā, pēc tam pārstartēt visus darbprocesus
fatal_error_backtraces = 0
```

Kļūdu žurnāli pēc PHP2Shell ir arī svarīgs pierādījums. Ja kopš 20.10.2026 uzkrājas atmiņas kļūdas vai pārtraukti darbprocesi, tas var norādīt uz uzbrukuma mēģinājumiem, bet var būt arī nekaitīgi iemesli. Saglabājiet žurnālus un izvērtējiet tos kopā ar piekļuves žurnāliem, kā aprakstīts ceļvedī [Tīmekļa servera žurnālu izvērtēšana pēc uzbrukuma](https://phpsos.de/lv/ratgeber/logfiles-auswerten/).

## Kā PHP SOS palīdz konkrēti?

- Mēs pārbaudām spēkā esošos kļūdu izvades un reģistrēšanas iestatījumus katrai vietnei un iestatām tos produkcijai piemērotus.
- Mēs ieviešam PHP2Shell pagaidu pasākumus atbilstoši PHP versijai un pārstartējam visus darbprocesus.
- Mēs nodrošinām kļūdu un piekļuves žurnālus no 20.10.2026 un izvērtējam tos uz neparastām pazīmēm.
- [Drošības monitoringa](https://phpsos.de/lv/leistungen/security-monitoring/) ietvaros mēs ziņojam par neparastu kļūdu uzkrāšanos, nevis ļaujam tai pazust žurnālā.


## Biežāk uzdotie jautājumi

**Kāda ir atšķirība starp Error un Exception?**  
Abi ievieš interfeisu Throwable. Exception paredzēts kļūdām, ko lietojumprogramma gaida un apstrādā, piemēram, neizdevies datubāzes savienojums. Error apzīmē PHP iekšējās kļūdas, piemēram, TypeError vai dalīšanu ar nulli.

**Vai display_errors produkcijā jāieslēdz?**  
Nē. Kļūdu ziņojumi pārlūkprogrammā atklāj ceļus, vaicājumus un dažkārt pieejas datus. Produkcijā display_errors jābūt Off un log_errors On, lai kļūdas nonāktu žurnālā, nevis pie apmeklētāja.

**Vai atmiņas pārpildi var noķert ar try/catch?**  
Nē. Ja skripts pārsniedz memory_limit, PHP to beidz ar fatālu kļūdu, ko nevar noķert kā izņēmumu. Tā parādās tikai kļūdu žurnālā, ja log_errors ir aktīvs.

**Kas ir fatal_error_backtraces?**  
Iestatījums, kas pastāv kopš PHP 8.5.0 un fatālām kļūdām pievieno backtrace. Pēc noklusējuma tas ir aktīvs. Kā pagaidu pasākumu pret PHP2Shell php.net PHP 8.5 min iestatīt to uz 0 un pēc tam PHP pārstartēt.

## Avoti

- [PHP rokasgrāmata: kļūdu apstrādes konfigurācija](https://www.php.net/manual/de/errorfunc.configuration.php)
- [PHP rokasgrāmata: klase Error](https://www.php.net/manual/de/class.error.php)
- [PHP rokasgrāmata: ErrorException](https://www.php.net/manual/en/class.errorexception.php)
- [PHP rokasgrāmata: set_exception_handler](https://www.php.net/manual/en/function.set-exception-handler.php)
- [php.net: drošības paziņojumi](https://www.php.net/)
