Na navigaci | Klávesové zkratky

Kompilační chyby v PHP: proč jsou stále problémem?

Programování v jazyce PHP byla vždycky trošku výzva, ale naštěstí prošlo mnohými změnami k lepšímu. Pamatujete na časy před verzí PHP 7, kdy skoro každá chyba znamenala fatal error, což aplikaci okamžitě ukončilo? V praxi to znamenalo, že jakákoli chyba mohla aplikaci zcela zastavit, aniž by programátor měl možnost ji zachytit a náležitě na ni reagovat. Nástroje jako Tracy využívaly magických triků, aby dokázaly takové chyby vizualizovat a logovat. Naštěstí s příchodem PHP 7 se tohle změnilo. Chyby nyní vyvolávají výjimky, jako jsou Error, TypeError a ParseError, které lze snadno zachytávat a ošetřit.

Avšak i v moderním PHP existuje slabé místo, kdy se chová stejně jako ve své páté verzi. Mluvím o chybách během kompilace. Ty nelze zachytit a okamžitě vedou k ukončení aplikace. Jedná se o chyby úrovně E_COMPILE_ERROR. PHP jich generuje na dvě stovky. Vzniká paradoxní situace, že když v PHP načteme soubor se syntaktickou chybou, což může být třeba chybějící středník, vyhodí zachytitelnou výjimku ParseError. Ovšem v případě, že kód je sice syntakticky v pořádku, leč obsahuje chybu odhalitelnou až při kompilaci (například dvě metody se stejným názvem), vyústí to ve fatální chybu, kterou zachytit nelze.

try {
	require 'cesta_k_souboru.php';
} catch (ParseError $e) {
	echo "Syntaktická chyba v PHP souboru";
}

Bohužel, kompilační chyby v PHP nemůžeme ověřit interně. Existovala funkce php_check_syntax(), která navzdory názvu odhalovala i kompilační chyby. Byla zavedena v PHP 5.0.0, ale záhy odstraněna ve verzi 5.0.4 a od té doby nikdy nebyla nahrazena. Pro ověření správnosti kódu se musíme spolehnout na linter z příkazové řádky:

php -l soubor.php

Z prostředí PHP lze ověřit kód uložený v proměnné $code třeba takto:

$code = '... PHP kód pro ověření ...';
$process = proc_open(
	PHP_BINARY . ' -l',
	[['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']],
	$pipes,
	null,
	null,
	['bypass_shell' => true],
);
fwrite($pipes[0], $code);
fclose($pipes[0]);
$error = stream_get_contents($pipes[1]);
if (proc_close($process) !== 0) {
	echo 'Chyba v PHP souboru: ' . $error;
}

Nicméně režie spouštění externího PHP procesu kvůli ověření jednoho souboru je docela velká. Ale dobrá zpráva přichází s verzí PHP 8.3, která přinese možnost ověřovat více souborů najednou:

php -l soubor1.php soubor2.php soubor3.php

Komentáře

  1. Robert #1

    avatar

    Anebo místo php -l soubor.php lze použít oblíbený eval 🙂 Zhruba nějak takto:

    qc_GetPhpSourceError.php
    <?php
    $Code = 'return true; ?>'.$_POST['Source'].'?><?php ';
    ini_set('display_errors', 1);
    error_reporting(E_ALL /*& ~E_NOTICE  .... jak kdo chce ...*/);
    eval ($Code);
    ?>

    A funkce na kontrolu je pak:
    <?php
    function CheckPhp($source)
    {
    $url = 'https://domena/cesta......./qc_GetPhpSourceError.php';
    $data = array('Source' => $source);
    $options = array(
        'http' => array(
            'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
            'method'  => 'POST',
            'content' => http_build_query($data)
        )
    );
    $context  = stream_context_create($options);
    $result = file_get_contents($url, false, $context);
    ....
    //A v $result buď nic není anebo je tam popis chyby.
    //A dá se z něj vyparsovat řádek a třeba tam přenést kurzor editoru
    }
    ?>

    Někdy v php 5.6 jsem to porovnával s php -l a zdálo se mi to lepší …

    před 5 měsíci | odpovědět | reagoval [2] David Grudl
  2. David Grudl #2

    avatar

    #1 Robert, všechna úskalí, které tento článek popisuje, platí jak pro require(), tak pro eval()

    před 5 měsíci | odpovědět

Napište komentář

Text komentáře
Kontakt

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--

phpFashion © 2004, 2024 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.