ГЛАВА 6. Переменные, константы, типы данных

Переменные 

В PHP принято не скупиться на объявление новых переменных, даже если можно обойтись и без них.

  • сценарий будет значительно читабельнее
  • интерпретатору это обходится довольно "дешево"

Правильное именование переменных

  • Имена переменных чувствительны к регистру: например, $my_variable — не то же самое, что $My_Variable или $MY_VARIABLE
  • Имена всех переменных должны начинаться со знака $ — так интерпретатору значительно легче "понять" и отличить их, например, в строках.
  • Также Имена переменных нужно писать исключительно на латинице с цифрами, хоть и можно на русском.

Копирование переменных

Переменные в PHP —могут содержать все, что угодно. Если в программе что-то хранится, то оно всегда хранится в переменной (исключение — константа, а начиная с PHP 7 — массив).... ... при присваивании переменная в большинстве случаев копируется один в один (исключение — копирование переменной, ссылающейся на объект или массив: в этом случае объект остается в единственном экземпляре, копируется лишь ссылка на него)... 

PHP не нужно ни описывать переменные явно, ни указывать их тип, он все это делает сам. Но иногда может ошибаться. Иногда нужно явно указывать, какой же тип имеет то или иное выражение.

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

Типы переменных

Тип переменной можно узнать при помощи вызова функции gettype($variable), которая примет значение, равное имени типа в строковом представлении.

integer (целое число) - стр. 124.

Целое число со знаком, размер которого зависит от разрядности PHP. Проверить максимальное значение можно так:

<?php 
  echo PHP_INT_MAX; // 9223372036854775807 в 64-битной системе
?>

 Подробно на стр. 128. книги, или на php.su, php.net

double (вещественное число) 

Числа с плавающей точкой имеют две формы записи. Обычная форма совпадает с принятой в арифметике, например, 346.1256.

Так же могут быть записаны как число в соответствующей степени числа 10, например 103, но т.к. в компьютерных программах нет возможности использовать символы верхнего регистра (3), поэтому конструкцию x10 записывают в виде символа e (экспонента), после которого указывается значение степени. Переменные $x и $y совершенно равнозначны:

<?php 
  $x = 0.00012; 
  $y = 1.2e-4; 
  $x = 346.1256; 
  $y = 3.461256e+2; 
?>

Так же есть допустимые пределы на использование чисел, выражение некоторых дробей, и точности в округлении:

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

Подробнее на стр. 129, на php.su и на php.net

string (строка текста)

  • Строка практически любой длины. 
  • строки могут содержать в себе также и нулевые символы
  • вполне реально прочитать в одну строку содержимое целого файла размером в несколько мегабайт (что часто и делается)
  • может быть обработана при помощи стандартных функций,
  • допустимо непосредственное обращение к любому ее символу.

Строка может быть определена четырьмя различными способами:

Одинарные кавычки - самый простой способ, но и малодейственный, кроме текста и самих (экранированных) кавычек ничего не обрабатывает.

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

Подробно на php.net и php.su 

array (ассоциативный массив) 

Набор из нескольких элементов, каждый из которых представляет собой пару вида ключ=>значение (символом => мы обозначаем соответствие определенному ключу какого-то значения).

Примерно выглядит это так:

// Создаст массив с ключами "0", "surname" и "name" 
$a = array( 
  0 => "Нулевой элемент", 
  "surname" => "Гейтс", 
  "name" => "Билл", 
);

echo $a["surname"];         // выведет "Гейтс" 
$a["1"] = "Первый элемент"; // создаст элемент и присвоит ему значение 
$a["name"] = "Вильям";   // присвоит существующему элементу новое значение

Стр. 130., на php.net, простые и ассоциативные на php.su и несколько примеров: php.su/array 

object (ссылка на объект)

Ссылка на объект, который реализует несколько принципов объектно-ориентированного программирования. Внутренняя структура объекта похожа на ассоциативный массив, за исключением того, что для доступа к отдельным элементам (свойствам) и функциям (методам) объекта используется оператор ->, а не квадратные скобки. Объекты подробно описываются в частях IV и V.

Объекты на php.su 

ВНИМАНИЕ!
Еще раз предупреждаем, что переменные в PHP хранят не сами объекты, а лишь ссылки на них. Это означает, что при копировании таких переменных (например, оператором $a = $obj) данные объекта в памяти не дублируются, и последующее изменение объекта $a повлечет за собой немедленное изменение объекта $obj.

resource (ресурс)

Некоторый ресурс, который PHP обрабатывает особым образом. Например: функ-
ция imageCreate() графической библиотеки GD создает в памяти новую "пустую" кар-
тинку указанного размера и возвращает ее идентификатор.

Resource это специальная переменная, содержащая ссылку на внешний ресурс. Ресурсы создаются и используются специальными функциями. Полный перечень этих функций и соответствующих типов ресурсов(resource) смотрите в приложении.

boolean (логический тип) 

Это простейший тип. boolean выражает истинность значения. Он может быть либо TRUE, либо FALSE.

Для указания boolean, используйте константы TRUE или FALSE. Обе они регистронезависимы.

<?php
$foo = True; // присвоить $foo значение TRUE
?>

Обычно, некоторый оператор возвращает boolean значение, которое потом передается управляющей конструкции.

<?php
// == это оператор, который проверяет
// эквивалентность и возвращает boolean
if ($action == "show_version") {
    echo "The version is 1.23";
}

// это необязательно...
if ($show_separators == TRUE) {
    echo "<hr>\n";
}

// ... потому что следующее имеет тот же самый смысл:
if ($show_separators) {
    echo "<hr>\n";
}
?>

Вообще, любое ненулевое число (и непустая строка), а также ключевое слово true символизирует истину, тогда как 0, пустая строка и слово false — ложь. Таким образом, любое ненулевое выражение (в частности, значение переменной) рассматривается в логическом контексте как истина.

Преобразование в булев тип

Для явного преобразования в boolean, используйте (bool) или (boolean). Однако, в большинстве случаев приведение типа необязательно, так как значение будет автоматически преобразовано, если оператор, функция или управляющая конструкция требует boolean аргумент.

<?php
var_dump((bool) "");        // bool(false)
var_dump((bool) 1);         // bool(true)
var_dump((bool) -2);        // bool(true)
var_dump((bool) "foo");     // bool(true)
var_dump((bool) 2.3e5);     // bool(true)
var_dump((bool) array(12)); // bool(true)
var_dump((bool) array());   // bool(false)
var_dump((bool) "false");   // bool(true)
?>

null (специальное значение) 

Специальное значение NULL представляет собой переменную без значения. NULL - это единственно возможное значение типа null.

Переменной можно присвоить специальную константу null, чтобы пометить ее особым образом. Тип этой константы — особый и называется также null. Это именно отдельный тип, и функция gettype(), которую мы вскоре рассмотрим, вернет для nullпеременной слово null.

Переменная считается null, если:

  • ей была присвоена константа NULL.

  • ей еще не было присвоено никакого значения.

  • она была удалена с помощью unset().

Написано также, что допускается запись константы прописными буквами NULL, но не рекомендовано стандартом PSR-2, хотя на PHP.net:

Существует только одно значение типа null - регистронезависимая константа NULL.

Действия с переменными

Вне зависимости от типа переменной над ней можно выполнять три основных действия.

Присвоение значения 

Переменной можно присвоить:

  • значение другой переменной (или значение, возвращенное функцией),
  • ссылку на другую переменную,
  • либо же константное выражение.

Если переменная первый раз встречается в программе, происходит ее инициализация. Исключение составляют объекты, которые инициализируются явно оператором new.

Как уже говорилось, за преобразование типов отвечает сам интерпретатор.

Кроме того, при присваивании старое содержимое и, что самое важное, тип переменной
теряются, и она становится абсолютно точной копией своего "родителя". То есть, если
мы массиву присвоим число, это сработает, однако весь массив при этом будет утерян.

Проверка существования

Можно проверить, существует ли (т. е. инициализирована ли) указанная переменная.
Выполняется это при помощи встроенной в PHP конструкции isset(). Например:

if (isset($my_var)) 
echo "Такая переменная есть. Ее значение $my_var";

Если переменная в данный момент не существует (т. е. нигде ранее ей не присваива-
лось значение либо же она была вручную удалена при помощи unset()), то isset() воз-
вращает ложь, в противном случае — истину.

Уничтожение

Уничтожение (разрушение) переменной реализуется оператором unset(). После этого переменная удаляется из внутренних таблиц интерпретатора, т. е. программа начинает выполняться так, как будто переменная еще не была инициализирована. (книга)

// разрушить одну переменную
unset ($foo);

// разрушить один элемент массива
unset ($bar['quux']);

// разрушить более одной переменной
unset ($foo1, $foo2, $foo3);

Применение unset() для работы с обычными переменными редко используют. Полезнее использовать его для удаления элемента в ассоциативном массиве.

Подробнее: php.suphp.net 

Определение типа переменной 

Кроме описанных действий существуют еще несколько стандартных функций, которые занимаются определением типа переменных и часто включаются в условные операторы.

  • is_int($a)
    Возвращает true, если $a — целое число. 134 Часть II. Основы языка PHP
  • is_double($a)
    Возвращает true, если $a — действительное число.
  • is_infinite($a)
    Возвращает true, если $a — бесконечное действительное число INF.
  • is_nan($a)
    Возвращает true, если $a — не допустимое числовое значение NAN.
  • is_string($a)
    Возвращает true, если $a является строкой.
  • is_numeric($a)
    Возвращает true, если $a является либо числом, либо строковым представлением числа (т.е. состоит из цифр и точки). Рекомендуется использовать данную функцию вместо is_integer() и is_double(), потому что над числами, содержащимися в строках, можно выполнять обычные арифметические операции.
  • is_bool($a)
    Возвращает true, если (и только если) $a имеет значение true или false.
  • is_scalar($a)
    Возвращает true, если $a — один и перечисленных выше типов. То есть, если это — простой тип (скалярный).
  • is_null($a)
    Возвращает true, если $a хранит значение null. Обратите внимание, что для такой
    переменной is_scalar() вернет false, а не true: null — это не скалярная величина.
  • is_array($a)
    Возвращает true, если $a является массивом.
  • is_object($a)
    Возвращает true, если $a содержит ссылку на объект.
  • gettype($a)
    Возвращает строки, соответственно, со значениями: "array", "object", "integer", "double", "string", "boolean", "null" и т. д. или "unknown type" в зависимости от типа переменной. Последнее значение возвращается для тех переменных, типы которых
    не являются встроенными в PHP (а такие бывают, например, при добавлении к PHP соответствующих модулей, расширяющих возможности языка).

 Установка типа переменной

Есть такая функция, которая пытается привести тип указанной переменной к одному из стандартных (например строку в целое число).

settype($var, $type)

Функция пытается привести тип переменной $var к типу $type ($type — одна из строк, возвращаемых gettype(), кроме boolean). Если это сделать не удалось (например, в $var
"нечисловая" строка, а мы вызываем settype($var, "integer")), возвращает false.

Помимо функции settype() существуют и более специализированные функции преобразования.

  • floatval($var)
    Функция преобразует переменную $var к вещественному числу. Для нее существует псевдоним doubleval(). Обе функции совершенно эквивалентны.
  • strval($var)
    Функция преобразует переменную $var в строку.
  • intval($var[, $base])
    Преобразует переменную $var в целочисленную переменную. По умолчанию числа
    приводятся к привычному нам десятичному формату. Однако при помощи необяза-
    тельного параметра $base можно получить результат, например, в восьмеричном ($base = 8) представлении:
    echo intval('42'); // 42
    echo intval('42', 8); // 34

Кроме указанных функций, в отношении переменных PHP действует C-синтаксис приведения типа, с указанием типа в круглых скобках перед переменной. Пример в книге на стр. 135.

Ссылочные переменные

Существуют три разновидности ссылок: жесткие, символические и ссылки на объекты (первые часто называют просто ссылками).

Жесткие ссылки

Жесткая ссылка - переменная, которая является синонимом другой переменной. Многоуровневые ссылки (т. е. ссылка на ссылку на переменнуюl) не поддерживаются.

Жесткие ссылки - это синонимы.

Чтобы создать жесткую ссылку, нужно использовать оператор =&. Например:

$a = 10; 
$b =& $a; // теперь $b - то же самое, что и $a 
$b = 0; // на самом деле $a = 0 
echo "b = $b, a = $a"; // выводит "b = 0, a = 0"

Ссылаться можно не только на переменные, но и на элементы массива (этим жесткие
ссылки выгодно отличаются от символических). Например:

$A = array( 
  'ресторан' => 'Китайский сюрприз', 
  'девиз'    => 'Nosce te computerus.' 
); 
$r =& $A['ресторан']; // $r - то же, что и элемент с индексом 'ресторан' 
$r = "Восход луны";    // на самом деле $A['ресторан'] = "Восход луны"; 
echo $A['ресторан'];   // выводит "Восход луны"

Впрочем, элемент массива, для которого планируется создать жесткую ссылку, может и не существовать. Рассмотрим листинг 6.2.

<?php ## Жесткая ссылка на несуществующий элемент массива 
  $A = array( 
    'вилка'     => '271 руб. 82 коп.', 
    'сковорода' => '818 руб. 28 коп.' 
  ); 
  $b =& $A['ложка'];  // $b - то же, что и элемент с индексом 'ложка' 
  echo "Элемент с индексом 'ложка': ".$A['ложка']."<br />"; 
  echo "Тип несуществующего элемента 'ложка': ".gettype($A['ложка']); 
?>

Результат:

Элемент с индексом 'ложка': 
Тип несуществующего элемента 'ложка': NULL

Хотя ссылке $b и не было ничего присвоено, в массиве $A создастся новый элемент с ключом 'ложка' и значением null (кстати, echo выводит NULL как пустую строку, не генерируя никаких предупреждений). То есть, жесткая ссылка на самом деле не может ссылаться на несуществующий "объект", а если делается такая попытка, то объект создается. 

Если $b присвоить значение, будет работать нормально (как в первом примере).

Сбор мусора

Когда создается новая переменная $a, PHP выделяет для нее память для хранения её значения и регистрирует $a в своих таблицах.

Когда создаём жесткую ссылку $r для переменной $a, PHP добавляет в свои внутренние таблицы новую запись — для переменной $r, но связывает с ней не новый участок памяти, а тот же, что был у переменной $a. В результате $a и $r ссылаются на одну и ту же область памяти, а потому являются синонимами.

Когда уничтожаем жесткую ссылку unset($r), "объект" на который ссылалась $r не удаляется и не освобождает память, а разрывается связь между ссылкой и "объектом" и ликвидирует запись о переменной $r из своих таблиц.
В самом деле, он не может уничтожить "объект": ведь $a до сих пор ссылается на него.

Итак, жесткая ссылка и переменная (объект), на которую она ссылается, совершенно равноправны: изменение одной влечет изменение другой. Оператор unset() разрывает связь между объектом и ссылкой, но объект удаляется только тогда, когда на него никто уже не ссылается.

Это и называется СБОР МУСОРА.

Символические ссылки $$

Символическая ссылка — это всего лишь строковая переменная, хранящая имя другой переменной. Применить оператор разыменования — второй знак $ перед именем ссылки.

Пример:

$right = "красная"; 
$wrong = "синяя"; 
$color = "right"; 
echo $$color; // выводит значение переменной $right ("красная") 
$$color = "несиняя"; // присваивает переменной $right новое значение 

Мы видим, что для использования обычной строковой переменной в качестве ссылки
нужно перед ней поставить еще один символ $. Это говорит интерпретатору, что надо
взять не значение самой переменной $color, а значение переменной, имя которой хра-
нится в переменной $color.

НЕ СОВЕТУЮТ использовать, т.к. получается очень не читабельно!

Ссылки на объекты

Сразу пример (Листинг 6.3):

<?php ## Ссылки на объекты 
  // Объявляем новый класс 
  class AgentSmith {}
  // Создаем новый объект класса AgentSmith 
  $first = new AgentSmith(); 
  // Присваиваем значение атрибуту класса 
  $first->mind = 0.123; 
  // Копируем объекты 
  $second = $first; 
  // Изменяем "разумность" у копии! 
  $second->mind = 100; 
  // Выводим оба значения 
  echo "First mind: {$first->mind}, second: {$second->mind}"; 
?>

Запустив код, и там и там выведет: 100 и 100. Т.к. переменная хранит не сам объект, а лишь ссылку на него.

* Или я не понял, или точно так же как и с жесткой ссылкой... 
Подробнее работу с объектами и ссылками на них мы рассмотрим в IV и V частях книги. 

Некоторые условные обозначения

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

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

Вот пример описания функции по имени FuncName:

<return_type> FuncName(<type1> $param1 [,<type1> $param2])

Функция делает то-то и то-то. Возвращает то-то.
Здесь должно быть приведено описание функции, возвращающей значение типа <return_type> и принимающей один или два аргумента (второй аргумент необязательный, на что указывают квадратные скобки). Тип первого параметра <type1>, а второго — <type2>. Описание возможных типов, которые мы здесь выделили угловыми скобками, приводится далее.

  • string
    Обычная строка или тип, который можно перевести в строку.
  • int, integer, long
    Целое число либо вещественное число (в последнем случае дробная часть отсекается), либо строка, содержащая число в одном из перечисленных форматов. Если строку не удается перевести в int, то вместо нее подставляется 0, и никакие предупреждения не генерируются!
  • double, float, number
    Вещественное число или целое число, или строка, содержащая одно из таких чисел.
  • boolean, bool
    Логический тип, который будет восприниматься либо как ложь (нулевое число, пустая строка или константа false), либо как истина (все остальное).
  • array
    Массив, в общем случае ассоциативный (см. главу 10), т. е. набор пар ключ => значение. Впрочем, здесь может быть передан и список list.
  • list
    Обычно это массив с целыми ключами, пронумерованными от 0 и следующими
    подряд. Так как список является разновидностью ассоциативного массива, то обычно вместо параметров функций типа list можно подставлять и параметры типа array. При этом, скорее всего, функция "ничего не заметит" и будет работать с этим массивом как со списком, "мысленно" пронумеровав его элементы. Можно также сказать, что список представляет собой упорядоченный набор значений (который можно, например, отсортировать по возрастанию), тогда как ассоциативный массив — упорядоченный набор пар значений, каждую из которых логически бессмысленно разъединять.
  • object
    Объект некоторой структуры. Чаще всего эта структура будет уточняться.
  • null
    Специальный тип NULL.
  • void
    Пожалуй, самый простой (но и самый концептуальный) тип, который применяется только для определения возвращаемого функцией значения. В обыденной жизни мы бы охарактеризовали void-функцию так: "Не возвращает ничего ценного".
    В PHP функция не может ничего не возвращать (так уж он устроен), поэтому практически все void-функции возвращают false (или пустую строку).
  • mixed
    Все, что угодно. Это может быть целое или дробное число, строка, массив или объект... Например, параметр типа mixed имеет стандартная функция gettype() или функция settype(). Если написано, что функция возвращает значение типа mixed, это значит, что тип результата зависит от операндов и уточняется при описании функции.
  • resource
    Значения этого типа возвращают различные функции, открывающие доступ к каким-либо внешним объектам в программе. Например, функция fopen() возвращает ресурс — дескриптор открытого файла. Для дальнейшей работы с файлом используется только его дескриптор.
  • callback
    Функция обратного вызова, обозначающая передаваемую внутрь другую функцию.
    Более подробно этот тип будет рассмотрен в главе 11.