Valery's Mlog

Mindlog of a Freak
November 5th, 2005 by Valery Dachev

PHP референции

PHP 5.0.5 излезе преди точно два месеца. Влизането на тази версия Debian (testing и unstable) бе форсирано, въпреки всичките проблеми, които излязоха наяве. Това направи по-старите версии недостъпни по сървърите. Целият хаос, който се създаде, обаче е заради несъобразителността на разработчиците и първоначалната толерантност на PHP към гре??ките им. За да има някаква съвместимост с преди??ни версии, има опции, с които да се поддържа този толеранс. Част от проблемите при работата на различен PHP софтуер са пряк резултат от неразбирането на разработчиците на референциите в PHP. Те са аналог на указателите в други езици и на Perl-референциите. Референциите се указват със знака амперсанд (&) пред доларовия знак за променлива. Ако в декларацията на дадена функция се укаже, че някой от аргументите е референция, то от там насетне се работи със съдържанието на реално подадената променлива, а не с копието и. Това дава две сериозни предимства:

  • не се прави копие на съдържанието на променливата при извикване на функцията. Това е особено важно, когато променливата съдържа големи по обем данни (например съдържанието на файл), защото спестява паметта необходима за копието, както и натоварването от самото копиране;
  • промяната на съдържанието се отразява и в контекста, където е извикана функцията, без да се налага тя да се връща като резултат;

Ще илюстрирам най-честите гре??ки, станали причина за това писание:

<?
    // NOTE: first parameter is a reference to the variable, not the variable itself
    function display( &$arr )
    {
       var_dump( $arr );
    }
    function &explode1( $delimiter, $str )
    {
       return explode( $delimiter, $str );
    }
    $str = ‘1|2|3’;
    $exploded = explode( ‘|’, $str );
    // ERROR: the result of a function can’t be referenced
    //! display( explode( ‘|’, $str ) );
    // WARNING: old syntax. references can now declared in function declarations only.
    //! display( &$exploded );
    // CORRECT: the variable $tmp holds the result, so we can pass it
    display( $tmp = explode( ‘|’, $str ) );
    // CORRECT: $exploded variable can be references
    display( $exploded );
    // CORRECT: the result of explode1() is declared to be a reference
    display( explode1( ‘|’, $str ) );
?>

Промяната в PHP 5.0.5 е, че първото извикване предизвиква гре??ка "Fatal error: Only variables can be passed by reference in…". Всъщност това е правилното поведение, защото резултатът от функцията не може да бъде достигнат с референция, макар в по-стари версии това да работе??е. При последния пример това обаче работи, функцията explode1() връща референция, която може директно да се подаде като аргумент на display(). Това е и най-често допусканата гре??ка в редица софтуер… като например SquirrelMail, Drupal, phpBB, много PEAR библиотеки и какво ли още не… Ре??ението е, или да се изчакат по-нови версии на софтуера, или да се запази по-старата PHP версия. ??стинска срамота е обаче за квалифицирани програмисти да проявяват такова неразбиране. На всичко отгоре имам и сериозното подозрение, че документацията на част от вградените в PHP функции не показва, че част от аргументите им трябва да са референции.

Примерът със стария синтаксис, в зависимост от настройките на самото PHP може да доведе до предупреждение "Call-time pass-by-reference has been deprecated – argument passed by value". Това означава, че поведението ще е различно от очакваното. Причината за това предупреждение е изключването или липсата на опцията "allow_call_time_pass_reference" в php.ini.

За съжаление обаче, тази промяна в PHP 5.0.5 поставя доста несъвместимости с по-стар или несъобразен PHP софтуер. Аз лично извадих късмет, че имам старите пакети (PHP 5.0.4) във /var/cache/apt/archives. Не знам какво ще правя по-нататък…

Comments

3 Responses to “PHP референции”
  1. Е не е толкова фатално – все пак това е Debian ;-)
    Т.е нужно е просто да се разходи?? после до http://snapshot.debian.net/

  2. Между другото опцията allow_call_time_pass_reference си я има от доста отдавна. Даже още в първата версия на php.ini-recommended (от 7-и април 2000г.) стойността му е Off. За съжаление малко от разработчиците/администраторите си дават труда да поразгледат php.ini-recommended. За радост FreeBSD porter-ите по подразбиране са сложили php.ini-recommended и съм свикнал да не ползвам, иначе на пръв поглед удобното предаване по адрес без да сме си го декларирали като такова. Абе това php се повече ми пада в очите ;)

  3. […] Днес се хванах най-накрая да обновя PHP на ма??ината си, което бях замразил на 5.0.4(-3 в Debian), заради проблемите с референциите, които се пръкваха във всевъзможен софтуер. Гре??ки от типа на “Fatal error: Only variables can be passed by reference in…” останаха само в инсталирания от пакет SquirrelMail 1.4.5(-2), които поправих наръка. ??нсталирах PHP 5.0.5(-3). На пръв поглед – никакви проблеми. Два сайта обаче прописнаха, че не работи file upload. Явно някакъв проблем с функциите за качване на файлове. ?? то мълчалив, просто защото файловете не се копират… […]

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: