Использование функций isset() и array_key_exists(). Как проверить существование файла на PHP? Проверка существования файла по URL-ссылке

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

Я тоже при разработке модуля столкнулся с этим вопросом. И нашел два варианта решения поставленной задачи.

Проверка существования файла по URL-ссылке

В PHP существует функция «fopen », с помощью которой можно открыть указанный URL.

Что мы делаем? Пытаемся открыть файл, и если нам это удается, значит, файл существует, а противном же случае – файла нет.

Реализация:

А что, если мы имеем не один файл, а несколько, так сказать, массив ссылок? Эта задача как раз и стояла изначально передо мной. И решение уже такой задачи следующее:

В этом случае мы получаем список только тех файлов, которые существуют.

Проверка существования локального файла

Под словом «локальный» подразумевается, что скрипт и файлы для проверки находятся на одном сервере. Если у вас довольно большой массив ссылок – этот вариант самый лучший для решения задачи, так как мы делаем не запрос на сторонний сервер, а сканирование указанных директорий.

В этом способе используется функция «file_exists», и по аналогии с предыдущим вариантом просто заменяется часть скрипта:

И то же самое для массива ссылок:

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

Кстати говоря, делая один из заказов, именно этим способом мне удалось просканировать порядка 135 000 файлов всего за пару секунд.

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

9.3.1. Наличие определения функции:function_exists

bool function_exists (string function_name)

Ищет функцию с именем f unct i on_name в общем списке определенных в системе функций. Возвращает true, если такая функция найдена, или false, если такой функции нет. При этом речь идет не только о пользовательских функциях, но и о системных, что позволяет эффективно проверять конфигурацию системы и предупреждать пользователя о необходимости перекомпиляции РНР-машины.

Так, приведенный ниже фрагмент проверяет наличие функции imap_open, которая доступна только при компиляции РНР с поддержкой ШАР:
if (function_exists("imap_open")) {
echo "IMAP функции доступны для работы.
\n";
} else {
echo "IMAP функции в PHP-машине отсутствуют.
\n";
}

9.3.2. Список определенных функций:get_defined_functions

array get_defined_functions ()

Функция возвращает многомерный массив, содержащий список всех определенных в системе функций, как встроенных, так и определенных пользователем. При этом встроенные функции помещаются в массив, адресуемый элементом $arr[" internal"],а пользовательские - в массив $аrr["usеr"], как это показано в листинге 9.1.

Рис. 9.3. Получить список всех функций в системе легко и просто.Но разбираться с этим списком вам придется самостоятельно


Листинг 9.1. Список функций, определенных в системе

Список функций, определенных в системеТIТLЕ>


// Функция для вывода одной строки внутренней таблицы
function myrow($data) {
echo "$data\n";
}
function print_list($vid) {
global $arr; // ссылаемся на внешний массив
?>

foreach ($arr[$vid] as $key) {
myrow($key); // Печатаем очередную строку
}
?>

}
$arr = get_defined_f unctions () ;


/tr>
Bcrpoeнныe функции Пользовательские функции





Результат выполнения этой программы приведен на рис. 9.3.

9.4. Регистрация специальных функций

Как правило, PHP-машина самостоятельно обрабатывает нештатные ситуации и состояния, требующие особой реакции. Однако при необходимости вы можете вмешаться в работу внутренних механизмов (см., например, раздел 15.6) включив собственные обработчики некоторых событий. В этом разделе мы рассмотрим, как включить эти обработчик в состав РНР-машины.

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

9.4.1 . Функция завершения:register shutdown function

int register_shutdown_f unction (string func)

Регистрирует функцию обработчика, вызываемого при штатном или аварийном завершении текущей PHP-программы. Подробное описание ее практического использования приведено в разделе 15.6.

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

9.4.2. Включение таймера: register_tick_function

void register_tick_function (string func [, mixed arg...])

Функция регистрирует обработчик func, который вызывается каждый тик времени. (Тик представляет собой разновидность «попугаев» и составляет примерно 1/20 секунды.) Этот обработчик используется преимущественно для организации периодического вывода информации о ходе выполнения вычислительного процесса.

9.4.3. Выключение таймера:unregister_tick_f unction

void unregister_tick_function (string func [, mixed arg...])

Эта функция противоположна по своему действию рассмотренной выше и предназначена для отключения обработчика «каждого тика».

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

Еще больше меня «порадовали» комментарии одного «незнакомого» знакомого, который удивился моему негодованию. Как оказалось, о существовании функции array_key_exists() он что-то слышал, но сам никогда ею не пользовался. Более того, где-то читал, что ее лучше заменять на isset() , так как последняя работает быстрее.

Собственно, об уровне квалификации PHP программистов сказано немало и добавить к этому нечего.

Инициализация и удаление переменной в PHP

В PHP переменная инициализируется в момент присваивания ей значения. Неинициализированной переменная считается в двух случаях:

  • ей не присваивалось никакого значения;
  • ей было присвоено значение типа NULL или она была передана функции unset() .

Присваивание NULL значения удаляет переменную, аналогично функции unset() , то есть делает ее неинициализированной.

Если попытаться использовать переменную, которая была удалена с помощью unset() , будет сгенерирована ошибка уровня E_NOTICE. С переменной, приведенной к NULL, такого не произойдет.

Функция isset()

Функция проверяет факт инициализации переменной. isset() вернет false, если передать ей в качестве параметра неинициализированную переменную. Тоже самое произойдет и с ключом массива, который имеет NULL значение. Для ключей массива действуют такие же правила приведения к NULL, как и для переменных.

$nullVar = null; var_dump($nullVar); $array = array("key_str" => "foo", "key_null" => null, "key_int" => 1); var_dump($array);

Результат:

null array "key_str" => string "foo" (length=3) "key_null" => null "key_int" => int 1

Функция array_key_exists()

Работа функции array_key_exists() похожа на isset() , но с той лишь разницей, что даже для ключа с NULL значением будет возвращено TRUE.

$array = array("key_str" => "foo", "key_null" => null, "key_int" => 1); var_dump(array_key_exists("key_null", $array)); // Вернет boolean true

Чтобы полностью удалить пару ключ-значение необходимо использовать unset() .

Для массива использование NULL значения ключа удобно, если наличие ключа требуется сохранить. Можно будет рассчитывать на контекст, в котором данный ключ будет использован. Например, это удобно при заполнении полей формы дефолтными значениями. Например, при использовании конструкции echo, NULL значение будет приведено к пустой строке.

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

Скорость работы isset() и array_key_exists()

О том, что array_key_exists() работает медленнее isset() пишут даже в комментариях к соответствующей странице PHP мануала. Жалуются на то, что более медленная работа array_key_exists() заметна на массивах с количеством пар ключ-значение, превышающих 200.

Ничего не остается, как прогнать банальный тест:

$testArray = array(883209 => 568420, 553314 => 266114, 133088 => 367615, // ...); $timerStart = microtime(); for ($i = 0; $i

Ассоциативный массив $testArray содержит 10 000 элементов . Это несколько больше, чем упомянутые 200 .

Далее прогоняем цикл с количеством итераций 100 000 . В теле цикла, по очереди, сначала делаем проверку с помощью isset() , затем с помощью array_key_exists() . Ключ, наличие которого проверяем, генерируется случайным образом, чтобы свести к минимуму вероятность его существования в массиве.

/>
isset() array_key_exists()
0.687027 0.728652

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

Функция isset() и свойства объекта

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

Class Foo { public $property = null; public function __construct() { } } $object = new Foo(); if (!isset($object->property)) { echo "property not exists"; }

Случай вопиющий, так как использование NULL в качестве дефолтного значения свойств – очень распространенная практика. И проверять наличие свойства объекта через isset() просто недопустимо.

Для проверки существования свойства у объекта в PHP существует функция property_exists() . Как и array_key_exists() , property_exists() вернет TRUE даже в том случае, если значение свойства приведено к NULL.

Также замечу, что для использования property_exists() не требуется наличие объекта класса. Проверку можно произвести по имени класса и имени свойства.

Class Foo { public $property = null; public function __construct() { } } var_dump(property_exists("Foo", "property")); // Вернет true

Такое вот занимательное программирование.

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

Функция в качестве первого параметра принимает имя класса или объект, а в качестве второго имя метода и возвращает "true", если объект или класс имеет данный метод, и "false" в противном случае.

Продемонстрируем работу функции "method_exists()" и создадим класс "myExists", который будет содержать два метода, открытый и закрытый.

Class myExists { public function method_public() { echo "Открытый метод"; } private function method_private() { echo "Закрытый метод"; } } $_Class_myExists = new myExists(); if(method_exists($_Class_myExists, "method_public")) { echo "

Метод "method_public" существует
"; } if(method_exists($_Class_myExists, "method_private")) { echo "
Метод "method_private" существует
"; } if(method_exists($_Class_myExists, "method_protected")) { echo "
Метод "method_protected" существует
"; } else { echo "
Метод "method_protected" не существует
"; }

В примере при помощи функции "method_exists()" в объекте класса "myExists" проверяется наличие существующих методов "method_public()", "method_private()" и не существующего метода "method_protected()". Результат:

Метод "method_public" существует Метод "method_private" существует Метод "method_protected" не существует

Как видно из результата проверки, функция возвращает "true" для каждого из методов, независимо от его спецификатора доступа, "false" возвращается только в том случае, если объект не обладает ни закрытым, ни открытым методом с таким именем.

В качестве первого аргумента функции "method_exists()" используется объект класса "$_Class_myExists", однако для проверки метода вовсе не обязательно создавать объект, достаточно передать имя класса. Пример:

Method_exists("myExists", "method_public");

При работе с функцией "method_exists()" следует учитывать, что она не может определить наличие динамических методов, созданных при помощи специального метода "__call()", "__callStatic()".

Помимо функции "method_exists()" можно воспользоваться альтернативной функцией "is_callable()", которая в отличие от "method_exists()", кроме проверки метода класса позволяет проверить существование функции, не входящей в состав класса.

Работая со сторонним классом, разработчик зачастую не знает досконально всех методов данного класса. Для того чтобы получить их полный список, можно воспользоваться функцией "get_class_methods()". В качестве первого параметра функция принимает имя класса, а возвращает массив его открытых методов. Следует подчеркнуть, что закрытые методы этой функцией не возвращаются. Пример:

$_all_pulic_method = get_class_methods($_Class_myExists); echo "

";
print_r($_all_pulic_method);
echo "
";

Результат:

Array ( => method_public)

Как можно видеть, закрытый метод "method_private()" не включён в результирующий массив. Динамические методы, которые эмулируются при помощи специального метода "__call()", "__callStatic()", также не попадают в список, получаемый при помощи функции "get_class_methods()".