21 ошибка программиста PHP. Часть 1

ОГЛАВЛЕНИЕ

20. Неверное применение семантики языка

Многие программисты используют в своей работе PHP, фактически не понимая тонкостей этого языка. Одна из тонкостей - разница между синтаксисом и семантикой PHP.

  • Синтаксис PHP: Представляет собой набор правил для определения элементов языка. Например, как мы определяем переменную? Ставим знак $ перед ее именем. Как определяем функцию? В общем случае, используя скобки, аргументы и т.п.
  • Семантика PHP: Представляет собой набор правил для применения синтаксиса. Например, возьмем функцию с двумя аргументами, что определяется ее синтаксисом. Причем в качестве аргументов ей следует передавать переменные строкового типа  - это определяется семантикой.

Заметьте: "следует". В языках с четким разделением типов (таких как Java или C) нет понятия "следует" (в общем случае, хотя бывают и исключения). В таком случае компилятор вынудит использовать переменные строго определенного типа.

Языки, в которых отсутствует само определение типов переменных, предоставляют больше гибкости в написании кода. Но, как бы то ни было, в случае неправильного использования семантики для большинства функций PHP следует ожидать появления сообщения об ошибке.

Возьмем кусок кода, который открывает файл и выводит его построчно:

<?php

$fp
= @fopen ( 'somefile.txt', 'r' )
or die ( 'Не могу открыть файл somefile.txt' );

while ($line = @fgets ( "$fp", 1024)) // Здесь ошибка!
{
print $line;
}

@fclose ("$fp") // И здесь тоже color
or die( 'Не могу закрыть файл somefile.txt' );

?>

В данном случае появится сообщение об ошибке типа:
"Warning: Supplied argument is not a valid File-Handle resource in tst.php on line 4"
("Внимание: аргумент не может являться дескриптором файла")

Это вызвано тем, что переменная $fp заключена в двойные кавычки, что однозначно определяет ее как строку, тогда как функция fgets() ожидает в качестве первого аргумента дескриптор, но не строку. Соответственно, вам следует использовать переменную, которая может содержать дескриптор.

Примечание: В данном случае строковый тип допустим синтаксически.

Для решения проблемы следует просто убрать двойные кавычки:

<?php
$fp = @fopen ( 'somefile.txt', 'r' )
or die ( 'Не могу открыть файл somefile.txt' );

while ( $line = @fgets ($fp, 1024) )
{
print $line;
}

@fclose ($fp)
  or die ( 'Не могу закрыть файл somefile.txt' );
?>

Как избежать неправильного приложения семантики?

В приведенном примере генерируется сообщение об ошибке. Но PHP предоставляет программисту больше свободы, чем другие, традиционные языки программирования. Это позволяет получать интересные результаты. Как минимум, теоретически возможно написать корректный код, неправильно используя семантику языка.

Но будьте осторожны, заигрывая с семантикой языка! Возможно появление трудноуловимых ошибок в программах. Если же вы все-таки решили поэкспериментировать, вам следует понимать три ключевых момента:

  • Типы: В PHP каждая переменная в любой момент времени относится к определенному типу. И это несмотря на тот факт, что ее тип можно свободно изменять. Другими словами, в языке PHP переменная не может существовать, при этом не относясь к определенному типу (и, соответственно, не обладая характеристиками, присущими этому типу). В PHP есть 7 основных типов переменных: Boolean, resource, integer, double, string, array и object.
  • Область видимости: В PHP переменные имеют область видимости, которая определяет то, откуда она может быть доступна и насколько долго будет существовать. Недопонимание концепции "области видимости" может проявляться в виде различного рода "плавающих" ошибок.
  • php.ini: При написании кода следует понимать, что не все пользователи имеют такую же конфигурацию программно-аппаратных средств, как и вы. Таким образом, совершенно необходимо лишний раз убедиться, сохраняется ли работоспособность вашего кода в той конфигурации, в которой программа должна работать, а не в той, в которой разрабатывалась.