Самоучитель PHP 4 - Котеров Д. В.
.pdf118 |
Часть III. Основы языка PHP |
Переменные в PHP — особые объекты, которые могут содержать в буквальном смысле все, что угодно. Если в программе что-то хранится, то оно всегда хранится в переменной (исключение — константа, которая, впрочем, может содержать только число или строку). Такого понятия, как указатель (как в Си), в языке не существует — при присваивании переменная копируется один-в-один, какую бы сложную структуру она ни имела. Тем не менее, в PHP версии 4 существует понятие ссылок — жестких и символических, их мы вскоре рассмотрим.
Как уже говорилось, в PHP не нужно ни описывать переменные явно, ни указывать их тип. Интерпретатор все это делает сам. Однако иногда он может ошибаться (например, если в текстовой строке на самом деле задано десятичное число), поэтому изредка возникает необходимость явно указывать, какой же тип имеет то или иное выражение.
Чуть чаще возникает потребность узнать тип переменной (например, переданной в параметрах функции) прямо во время выполнения программы. В этой связи давайте посмотрим, какие же типы данных понимает PHP.
Типы переменных
PHP непосредственно поддерживает 5 типов переменных, которые я здесь перечислю и коротко опишу.
integer
Целое число со знаком, обычно длиной 32 бита (от –2 147 483 648 до 2 147 483 647, если это еще кому-то может быть интересно).
double
Вещественное число довольно большой точности (ее должно хватить для подавляющего большинства математических вычислений).
string
Строка любой длины. В отличие от Си, строки могут содержать в себе также и нулевые символы, что никак не повлияет на программу. Иными словами, строки можно использовать для хранения бинарных данных. Длина строки ограничена только размером свободой памяти, так что вполне реально прочитать в одну строку целый "объемистый" файл размером так килобайтов 200—300 (что часто и делается). Строка легко может быть обработана при помощи стандартных функций, можно также непосредственно обратиться к любому ее символу.
array
Ассоциативный массив (или, как его часто называют, хэш, хотя для PHP такое понятие совсем не подходит). Это набор из нескольких элементов, каждый из которых представляет собой пару вида ключ=>значение (символом => я обозначаю соответ-
Глава 7. Переменные, константы, выражения |
119 |
ствие определенному ключу какого-то значения). Доступ к отдельным элементам осуществляется указанием их ключа. В отличие от массивов Си, ключами здесь могут служить не только целые числа, начиная с нуля, но и любые строки. Например, вполне возможно существование таких команд:
// создаст массив с ключами "0", "a", "b" и "c" $a=array(0=>"zzzz", "a"=>"aaa", "b"=>"bbb", "c"="ccc");
echo $a["b"]; |
// выведет "bbb" |
$a["1"]="qq"; |
// создаст новый элемент в массиве и присвоит ему "qq" |
$a["a"]="new_aaa"; |
// присвоит существующему элементу "new_aaa"; |
Забегая вперед, скажу, что оператор array() создает массив, элементы которого перечислена в его скобках.
object
Объект, реализующий несколько наиболее простых принципов объектноориентированного программирования. Внутренняя структура объекта похожа на хэш, за исключением того, что для доступа к отдельным элементам и функциям используется оператор ->, а не квадратные скобки. Про объекты мы еще поговорим в будущем, когда разберемся наконец с основами языка.
Логические переменные
Существует и еще один гипотетический тип переменных — логический. Логическая переменная может содержать одно из двух значений: false (ложь) или true (истина). Любое ненулевое число (и непустая строка), а также ключевое слово true символизирует истину, тогда как 0, пустая строка и слово false — ложь. Таким образом, любое ненулевое выражение (в частности, значение переменной) рассматривается в логическом контексте как истина. Вы можете пользоваться константами false и true в зависимости от логики программы.
Ключевые слова false и true — не совсем обычные константы. Раньше я говорил, что false является просто синонимом для пустой строки, а true — для единицы. Именно так они выглядят, если написать следующие операторы:
echo false; // выводит пустую строку, т. е. ничего не выводит echo true; // выводит 1
Теперь давайте рассмотрим такую программу (листинг 7.1).
Листинг 7.1. Логические величины
<? $a=100;
if($a==1) echo "переменная равна 1!<br>" if($a==true) echo "переменная истинна!<br>"
120 |
Часть III. Основы языка PHP |
?>
Если бы true была в точности равна константе 1, то вывелись бы обе строки, не правда ли? А отображается только последняя. Это говорит о том, что не все так просто. Мы видим, что в операторах сравнения (например, в операторе сравнения на равенство ==, а также в операторах >, < и т. д.) PHP интерпретирует один из операндов как логический, если другой также логический. Следующий пример (листинг 7.2) показывает, что, вообще говоря, PHP хранит для каждой переменной признак, является ли она логической.
Листинг 7.2. Логические переменные
<? $a=100; $b=true;
echo "a = $a<br>"; echo "b = $b<br>";
if($a==$b) echo 'а "равно" b!'; ?>
Как ни странно, но программа печатает, что "а=100 и b=1", а затем с гордостью заявляет, что "a равно b". Хотя в данном примере мы прекрасно понимаем, что так и должно быть (потому что на самом-то деле переменные сравниваются как логические), поэтому будьте осторожны, когда вместо $a используется, например, число, возвращенное функцией. Иначе это может породить ошибку, которая "убьет" несколько часов на ее поиски.
Конечно, при выполнении арифметических операций над логической переменной она превращается в обычную, числовую переменную. Однако при написании этой книги я наткнулся на интересное исключение: по-видимому, операторы ++ и -- для увеличения и уменьшения переменной на 1 не работают с логическими переменными (лис-
тинг 7.3):
Листинг 7.3. Особенности операторов ++ и --
<? $b=true;
echo "b: $b<br>"; $b++;
echo "b: $b<br>"; ?>
Глава 7. Переменные, константы, выражения |
121 |
Эта программа выводит оба раза значение 1, во всяком случае, в моей версии
PHP 4.03.
Некоторые особенности работы с логическими переменными вполне могут из- мениться в следующих версиях PHP. Их описание приведено здесь лишь с од- ной целью: уберечь вас от возможных ошибок, которые трудно будет найти в программе.
Действия с переменными
Вне зависимости от типа переменной, с ней можно делать три основных действия.
Присвоение значения
Мы можем присвоить переменной значение другой переменной (или значение, возвращенное функцией), ссылку на другую переменную, либо же константное выражение (за исключением объектов, для которых вместо этого используется оператор new). Как уже говорилось, за преобразование типов отвечает сам интерпретатор. Кроме того, при присваивании старое содержимое и, что самое важное, тип переменной теряются, и она становится абсолютно точной копией своего "родителя". То есть, если мы массиву присвоим число, это сработает, однако весь массив при этом будет утерян.
Проверка существования
Можно проверить, существует ли (то есть, инициализирована ли) указанная переменная. Осуществляется это при помощи оператора IsSet(). Например:
if(IsSet($MyVar))
echo "Такая переменная есть. Ее значение $MyVar";
Если переменной в данный момент не существует (то есть нигде ранее ей не присваивалось значение, либо же она была вручную удалена при помощи Unset()), то IsSet() возвращает ложь, в противном случае — истину.
Важно помнить, что мы не можем использовать неинициализированную переменную в программе — иначе это породит предупреждение со стороны интерпретатора (что, скорее всего, свидетельствует о наличии логической ошибки в сценарии). Конечно, предупреждения можно выключить, тогда все неинициализированные переменные будут полагаться равными пустой строке. Однако я категорически не советую вам этого делать — уж лучше лишняя проверка присутствия в коде, чем дополнительная возня с "отлавливанием" возможной ошибки в будущем. Если вы все же захотите отключить это злополучное предупреждение (а заодно и все остальные), лучше ис-
122 |
Часть III. Основы языка PHP |
пользовать оператор отключения ошибок @, который действует локально (о нем мы тоже вскоре поговорим).
Уничтожение
Уничтожение переменной реализуется оператором Unset(). После этого действия переменная удаляется из внутренних таблиц интерпретатора, т. е. программа начинает выполняться так, как будто переменная еще не была инициализирована. Например:
//Переменной $a еще не существует $a="Hello there!";
//Теперь $a инициализирована
//... какие-то команды, использующие $a echo $a;
//А теперь удалим переменную $a
Unset($a);
// Теперь переменной $a опять не существует echo $a; // Ошибка: нет такой переменной $a
Впрочем, применение Unset() для работы с обычными переменными редко бывает целесообразно. Куда как полезнее использовать его для удаления элемента в ассоциативном массиве. Например, если в массиве $A нужно удалить элемент с ключом for_del, это можно сделать так:
Unset($A["for_del"]);
Теперь элемент for_del не просто стал пустым, а именно удалился, и последующий перебор элементов массива его не обнаружит.
Определение типа переменной
Кроме этих трех действий существуют еще несколько стандартных функций, которые занимаются определением типа переменных и часто включаются в условные операторы. Вот они.
ris_integer($a)
Возвращает true, если $a — целое число.
ris_double($a)
Возвращает true, если $a — действительное число.
ris_string($a)
Возвращает true, если $a является строкой.
ris_array($a)
Возвращает true, если $a является массивом.
Глава 7. Переменные, константы, выражения |
123 |
ris_object($a)
Возвращает true, если $a объявлена как объект.
ris_boolean($a)
Возвращает true, если $a определена как логическая переменная.
rgettype($a)
Возвращает строки, соответственно, со значениями: array, object, integer, double, string, boolean или unknown type в зависимости от типа перемен-
ной.
Последнее значение возвращается для тех переменных, типы которых не являются встроенными в PHP (а такие бывают, например, при добавлении к PHP соответствующих модулей, расширяющих возможности языка). Я на них останавливаться не буду, т. к. в будущем наверняка появятся сотни таких модулей для PHP.
Установка типа переменной
Существует функция, которая пытается привести тип указанной переменной к одному из стандартных (например, вам может понадобиться перевести строку в целое число). Вот она.
settype($a,$type)
Функция пытается привести тип переменной $a строк, возвращаемых gettype(), кроме boolean пример, в $a "нечисловая" строка,
($a,"integer")), возвращает false.
к типу $type ($type — одна из ). Если это сделать не удалось (на- а мы вызываем settype
Оператор присваивания
Сильно не ошибусь, если скажу, что нет на свете такой программы, в которой не было бы ни одного оператора присваивания. И в PHP-программе этот оператор, конечно же, тоже есть. Мы уже с ним встречались — это —знак равенства =:
$имя_переменной=значение;
Как видите, разработчики PHP пошли по линии Си в вопросе операторов присваивания (и проверки равенства, которая обозначается ==), чем, я уверен, привнесли свой вклад в размножение многочисленных ошибок. Например, если в Си мы пишем
if(a=b) { ... }
вместо
if(a==b) { ... }
124 |
Часть III. Основы языка PHP |
(пропуская ненароком один символ равенства), то компилятор выдаст нам по крайней мере предупреждение. Иначе обстоит дело в PHP: попробуйте как-нибудь на досуге написать:
$a=0; $b=1;
if($a=$b) echo "a и b одинаковы"; else echo "a и b различны";
Интерпретатор даже не "пикнет", а программа восторженно заявит, что "a и b одинаковы", хотя это, очевидно, совсем не так (дело в том, что $a=$b так же, как и $a+$b, является выражением, значение которого есть правая часть оператора присваивания, равная в нашем примере 1).
Почему разработчики PHP пошли таким путем, хотя, я уверен, отлично пони- мали его недостатки (двух мнений тут быть просто не может)? Что бы им стои- ло вместо = использовать (например, как в Паскале) :=, а вместо == — =? Я не знаю. Зато знаю, что в PHP есть еще несколько "ляпов" (только давайте не будем разжигать религиозных войн по поводу оператора == — каждый про- граммист волен иметь свое мнение), перенятых из Си. Так что призываю вас быть предельно внимательными — тут могут поджидать очень даже неприят- ные сюрпризы.
Ссылочные переменные
Хотя в PHP нет такого понятия, как указатель (что, возможно, к лучшему, а скорее всего — нет), все же можно создавать ссылки на другие переменные. Существует две разновидности ссылок: жесткие и символические (первые часто называют просто ссылками). Жесткие ссылки появились лишь в PHP версии 4 (в третьей версии существовали лишь символические ссылки).
Жесткие ссылки
Жесткая ссылка представляет собой просто переменную, которая является синонимом другой переменной. Многоуровневые ссылки (то есть, ссылка на ссылку на переменную, как это можно делать, например, в Perl) не поддерживаются. Так что, думаю, не стоит воспринимать жесткие ссылки серьезнее, чем синонимы.
Чтобы создать жесткую ссылку, нужно использовать оператор & (амперсанд). Например:
$a=10;
$b = &$a; // теперь $b — то же самое, что и $a $b=0; // на самом деле $a=0
echo "b=$b, a=$a"; // выводит "b=0, a=0"
Глава 7. Переменные, константы, выражения |
125 |
Ссылаться можно не только на переменные, но и на элементы массива (этим жесткие ссылки выгодно отличаются от символических). Например:
$A=array('a' => 'aaa', 'b' => 'bbb');
$b=&$A['b']; // теперь $b — то же, что и элемент с индексом 'b' массива $b=0; // на самом деле $A['b']=0;
echo $A['b']; // выводит 0
Впрочем, элемент массива, для которого планируется создать символическую ссылку, может и не существовать. Как в следующем случае:
$A=array('a' => 'aaa', 'b' => 'bbb');
$b=&$A['c']; // теперь $b — то же, что и элемент с индексом 'c' массива echo "Элемент с индексом 'c': (".$A['c'].")";
В результате выполнения этой программы, хотя ссылке $b и не было ничего присвоено, в массиве $A создастся новый элемент с ключом c и значением — пустой строкой (мы можем это определить по результату работы echo). То есть, жесткая ссылка на самом деле не может ссылаться на несуществующий объект, а если делается такая попытка, то объект создается.
Попробуйте убрать строку, в которой создается жесткая ссылка, и вы тут же получите сообщение о том, что элемент с ключом c не определен в массиве $A.
И все же, жесткая ссылка — не абсолютно точный синоним объекта, на который она ссылается. Дело в том, что оператор Unset(), выполненный для жесткой ссылки, не удаляет объект, на который она ссылается, а всего лишь разрывает связь между ссылкой и объектом.
В этой трактовке любую переменную, даже только что созданную, можно рас- сматривать как жесткую ссылку. Просто она — единственная, кто ссылается на недавно построенный объект.
Итак, жесткая ссылка и переменная (объект), на которую она ссылается, совершенно равноправны, но изменение одной влечет изменение другой. Оператор Unset() разрывает связь между объектом и ссылкой, но объект удаляется только тогда, когда на него никто уже не ссылается.
Жесткие ссылки удобно применять при передаче параметров функции и возврате значения из нее. Как это делается, мы рассмотрим в главе, описывающей возможности создания функций на PHP.
126 |
Часть III. Основы языка PHP |
Символические ссылки
Символическая ссылка — это всего лишь строковая переменная, хранящая имя другой переменной. Чтобы добраться до значения переменной, на которую ссылается символическая ссылка, необходимо применить оператор разыменования — дополнительный знак $ перед именем ссылки. Давайте разберем пример:
$a=10; $b=20; $c=30;
$p="a"; // или $p="b" или $p="c" (присваиваем $p имя другой переменной) echo $$p; // выводит переменную, на которую ссылается $p, т. е. $a $$p=100; // присваивает $a значение 100
Мы видим, что для того, чтобы использовать обычную строковую переменную как ссылку, нужно перед ней поставить еще один символ $.Это говорит интерпретатору, что надо взять не значение самой $p, а значение переменной, имя которой хранится в переменной $p.
Все это настолько редко востребуется, что вряд ли стоит посвящать теме символических ссылок больше внимания, чем это уже сделано. Думаю, использование символических ссылок — лучший способ запутать и без того запутанную программу, поэтому старайтесь их избегать, как огня.
Возможно, тем, кто хорошо знаком с файловой системой Unix, термины "жест- кая" и "символическая" ссылка напомнили одноименные понятия, касающиеся файлов. Аналогия здесь почти полная. Об этом же говорят и сами разработчи- ки PHP в официальной документации.
Некоторые условные обозначения
Как мы уже знаем, в PHP нет необходимости указывать тип какой-либо переменной или выражения явно. Однако, как мы видели, с каждой величиной в программе все же ассоциирован конкретный тип, который, впрочем, можно поменять в процессе выполнения программы. Такие "подмены" будут вполне осмысленными, если, например, мы к строке "20" прибавим число 10 и получим результат 30 (а не "2010") — это хороший пример того, как PHP выполняет преобразования из числа в строку и наоборот.
Но представьте себе, что мы хотим привести тип переменной $a к числу, а она на самом деле — массив. Ясно, что такое преобразование лишено всякого смысла — о чем вам и сообщит (в лучшем случае) PHP, если вы попытаетесь, например, прибавить $a к 10. А может и не сообщить (скажем, если перевести массив в строку, то всегда получится строка "Array"). В то же время, дальше, когда мы будем рассмат-
Глава 7. Переменные, константы, выражения |
127 |
ривать стандартные функции и операторы PHP (которых, кстати, очень много), мне в большинстве мест придется разъяснять, какой тип имеет тот или иной параметр функции или оператора, причем все другие несовместимые с ним типы должны быть исключены. Также было бы полезным обозначить явно тип возвращаемого значения функций. В этой связи я, подражая оригинальной документации по PHP, буду указывать типы переменных и функций там, где это необходимо, а также некоторые другие метасимволы. Вот пример описания функции по имени FuncName:
<return_type> FuncName(<type1> $param1 [,<type1> $param2])
Функция делает то-то и то-то. Возвращает то-то.
Здесь должно быть приведено описание функции, возвращающей значение типа <return_type>, и принимающей один или два аргумента (второй аргумент необязательный, на что указывают квадратные скобки). Тип первого параметра <type1>, а второго — <type2>. Описание возможных типов, которые я здесь выделил угловыми скобками, приводится в следующих подразделах.
string
Обычная строка, или тип, который можно перевести в строку.
int, long
Целое число, либо вещественное число (в последнем случае дробная часть отсекается), либо строка, содержащая число в одном из перечисленных форматов. Если строку не удается перевести в int, то вместо нее подставляется 0, и никаких предупреждений не генерируется!
double, float
Вещественное число, или целое число, или строка, содержащая одно из таких чисел.
bool
Логический тип, который будет восприниматься либо как ложь (нулевое число, пустая строка или константа false), либо как истина (все остальное). Обычно редко указывается этот тип (вместо него пишут int, хотя это и неверно), но я все же постараюсь применять его там, где это возможно.
array
Массив, в общем случае ассоциативный (см. ниже). То есть набор пар ключ=>значение. Впрочем, здесь может быть передан и список list.
