Суббота, 28.12.2024, 13:00
Приветствую Вас Гость

Меню сайта
Web-программирование
Категории раздела
Наш опрос
Какой браузер Вы используете?
Всего ответов: 1423
Статистика

Анализ веб сайтов
Главная » Статьи » Статьи о PHP

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

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

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

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

В этой статье, состоящей из трех частей, я описываю 21 ошибку, которые, насколько мне известно, совершают наиболее часто, и указываю степень их опасности от малой до критической. Я предлагаю решения, советы и/или комментарии, как избегать их, в дополнение к тем трюкам, которые я узнал за эти годы.

Эта серия состоит из следующих трех статей:

Часть 1: Описывает первые 7 "школьных" ошибок (№21-15, в порядке, обратном их серьезности) по нашему рейтингу. Совершение этих ошибок хоть и не критично, приведет к замедлению кода и усложнению его поддержки.

Часть 2: Описывает следующие 7 "серьзных" ошибок, №14-8 по нашему рейтингу. Совершение этих ошибок значительно увеличит время работы программы, снизит надежность и защищенность, в дополнение к усложнению поддержки кода.

Часть 3: Описывает последние 7 "смертельных" ошибок. Эти ошибки концептуальны в своей природе и могут являться первопричиной ошибок, описанных в части 1 и 2. Они включают грубые промахи, такие как малое время, отведенное на разработку и не просматривание полученного кода.

14. Отступление от Правил Именования
Одна из наиболее серьезных ошибок, которую может совершить программист - применять неправильные методы именования. Я участвовал в проектах, на которые приходилось тратить безумное количество времени лишь потому, что программисту пришло в голову назвать переменные $fred и $barney вместо более логичных $email и $name. Я имею в виду проект, в котором программист-придурок решил назвать все переменные в стиле мультфильма про Флинстоунов (кроме шуток). Для создания читабельных скриптов важно, как вы обзываете свои переменные и функции. Многие программисты совершают следующие ошибки:

Имена слишком длинные или короткие.
Не отвечают содержанию.
Не учитывают существование разницы между заглавными и строчными символами.
Мешают читабельности кода (в частности, функций).
Именование Переменных

Разница в Регистре
В PHP имеет значение регистр текста, т.е., $user и $User - совершенно разные записи. Некоторые пользователи используют эту особенность, создавая переменные с таким же названием, но набранные в другом регистре. Регистр никогда не должен использоваться для различая между именами переменных. Каждое имя само по себе должно быть абсолютно уникальным.

Слишком короткие имена
Многие пользователи назначают своим переменным название-акронимы, а потом забывают что же они имели ввиду. Имена переменных должны описывать то, что они содержат, используя или полные слова или понятные аббревиатуры.

Слишком длинные имена
С другой стороны, некоторые пользователи используют слишком длинные имена переменных. Обычно имя переменной не должно быть длиннее двух слов. Два слова могут быть разделены либо символом '_', либо путем написания второго слова с заглавной буквы.

Хорошие Примеры
Далее следуют хорошие примеры имен переменных:

<?php
$username = 'sterling';
$password = 'secret';

$teachers = array ('Sadlon',
'Lane',
'Patterson',
'Perry',
'Sandler',
'Mendick',
'Zung');

foreach ($teachers as $teacher);
?>

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

<?php
$username_for_database = 'sterling';
$guMbi = 'secret'; // for the $password

$thelastnamesofteachers = array ('Sadlon',
'Lane',
'Patterson',
'Perry',
'Sandler',
'Mendick',
'Zung');

foreach ($thelastnamesofteachers as $TeaChER);
?>

Именование Функций

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

Использование Глаголов
Функции PHP эквиваленты используемым в речи глаголам. Имена функций таким образом должны бы ориентированы на действие. Также они должны быть определены в настоящем времени. К примеру, если у вас есть функция, выбирающая случайное число методом Гаусса, ее название должно определять, что она использует распределение Гаусса так: generate_gaussian_rand(). Обратите внимание на использование глагола действия в имени функции. Это позволяет описать функцию по ее содержанию.

<?php
list ($num1, $num2) = generate_gaussian_rand ();
list ($num3, $num4) = generate_gaussian_rand ();
?>

Сравните:

<?php
list ($num1, $num2) = gaussian_rand_generator ();
list ($num1, $num2) = gaussian_rand_generator ();
?>

Почувствовали разницу? Во втором примере в название функции использовано существительное, а не глагол действия. И хотя назначение функции все равно угадывается, ее название препятствует читабельности кода. Используйте глаголы!

13. Не Продумано: Базы Данных и SQL
Просто поразительно, сколько способов люди умудряются придумать, чтобы связаться с базой и получить выборку. Мне пришлось столкнуться с комбинациями if с циклами do:while, множественными вызовами, и помещением функций sql_result() в цикл for. Интересно, что они хотели этим добиться?

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

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

Этот раздел раскрывает следующие аспекты:

Неверное использование функций базы данных
Неверное использование SQL: Не Обрабатывается То Что Надо
Использование PHP для сортировки результатов
Неверное использование функций базы данных

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

<?php
if (!($row = sql_fetch_row ($result))) {
print "An error occurred: no rows found";
exit;
}

do {
print "$row[0]: $row[1]\n<br>\n";
} while ($row = sql_fetch_row ($result));
?>

Примечание: В вышепредставленном примере, $result означает ссылку или указатель на выборку, полученную по запросу. Другими словами, запрос уже был отправлен, а выборка получена из базы данных. Примеры описывают эффективность работы с полученными данными.

В этом коде есть пара проблем:

Проверяет случай отсутствия рядов, используя fetch.
Не сохраняет результат в ассоциативный массив.
Проверка на Отсутствие Рядов ($result): Неверный способ
Используя sql_fetch_row(), мы воспользовались не явно выраженным методом определения наличия совпадений в $result. Более правильный и понятный метод - подсчет числа рядов в $result с использованием sql_num_rows(), как показано ниже:

<?php
if (sql_num_rows ($result) <= 0 ) {
print "An error occurred: no rows found";
exit;
}

while ($row = sql_fetch_row ($result)) {
print "$row[0]: $row[1]\n<br>\n";
}
?>

Избавление от цикла Do...While
Первое и главное - омерзительный цикл do..while больше не нужен, поскольку при использовании sql_num_rows() при проверке выборки на наличие записей мы не используем первую запись. В программе PHP (пример которой представлен выше), если выборка была не пустой, первый ее ряд должен был получаться и обрабатываться функцией sql_fetch_row() внутри условия if. Структура do..while в данных условиях необходима, поскольку обработка данных, полученных из базы, сдвигает указатель. Таким образом, вы должны обработать первый ряд ("do") сразу после его извлечения. Следующее обращение к fetch выдаст второй ряд и так далее. Почему цикл do..while считается "омерзительным"?

Пример отражает только одно действие цикла - простой print. Представьте, что было бы, если бы в цикле было 10 действий. Человеку, просматривающему код, пришлось бы искать строчку while после обнаружения do. Ненавижу.
Обычно условия while начинают структуру, а не заканчивают ее. То есть, человеку, просматривающему код, нужно быть очень внимательным, чтобы понять что while в данном случае является окончанием структуры do..while, а не началом обычного цикла.
Делайте все ясно и понятно
Для пустого набора результатов sql_num_rows() сразу переходит к результату, а sql_fetch_row() нет:

sql_fetch_row() говорит "Обнаружено отсутствие записей в выборке. Это значит, что их нет".
sql_num_rows() говорит "Число записей в результате 0."
Но чем различаются данные сообщения? Рассмотрим тоже сравнение, но на этот раз в контексте условия if, и выраженного Псевдо-кодом:

if(!($row = sql_fetch_row($result))){Print Error}:
Достать ряд из выборки.
Если результат пуст, назначить $row значение 0; Булевое значения нуля Ложно, поэтому !(0) = Истинно; Вывести сообщение об ошибке.
В противном случае, если выборка не пуста, извлечь первый ряд и положить его в $row; $row не ноль и его Булевое значение Истинно. Следовательно !(Истинно) = Ложно, продолжаем действовать по структуре do..while.
if((sql_num_rows($result)<= 0){Print Error}:
Посчитать число рядов в выборке.
Если меньше или равно 0, вывести сообщение об ошибок.
В противном случае, продолжить.
Какой вариант легче понять? Ясное дело, подсчет числа рядов гораздо понятнее. Какова разница на практике? Ведь на одном упрощении оператора if особо ничего не выиграешь. Там не менее, в случае, когда есть 10,000 строк кода, потратив время и подумав о том, как можно написать код понятней, можно избежать многочасового анализа в будущем. Есть и дополнительные преимущества, например более быстрый и понятный процесс разработки.

Когда ваш DBMS (СУБД) не поддерживает sql_num_row()
Некоторые DBMS (СУБД) могут не поддерживать функцию sql_num_row(). Выражаю свои соболезнования, если Вам досталась такая. Вам придется проверять случай отсутствия записей в выборке, перебирая ряды. Тем не менее, даже в данных условиях целесообразней применять булевое выражение, как показано на примере ниже:

<?php
$found = false;
while ($row = sql_fetch_array($result)) {
$found = true;
}

if (!$found) {
print "Error";
}
?>

Перебор выборки: повышение эффективности
Вторая проблема с этим кодом заключает в использовании функции sql_fetch_row() для перебора выборки. Функция sql_fetch_row() лишь возвращает обычный массив, индексированный по номерам записей. sql_fetch_array() в тоже время возвращает массив, индексированный и по номерам, и по названием записей, как показано на примере:

<?php
$row = sql_fetch_array ($result);
print $row[1]; // Second column
print $row[name]; // The name column
?>

Примечание: По некоторым правилам при указании строчного аргумента требуется писать его в кавычках. В случае со строчкой name выше, и далее в этой статье, было решено не использовать их.

С точки зрения разработчика, как функция выдаст программисту более полезный результат? Индексированные по названиям массив позволяет читателю точно понимать, что извлекается из базы данных, просто почитав код, как показано на исправленном примере ниже:

<?php
if (sql_num_rows ($result) <= 0) {
print "An error occurred: no rows found";
exit;
}

while ($row = sql_fetch_array ($result)) {
print "$row[name]: $row[phone_number]\n<br>\n";
}
?>

Когда следует использовать sql_fetch_row($result)
Я не очень люблю функцию sql_fetch_row(). Тем не менее, есть один случай, в котором ее можно использовать без понижения читабельности - когда запрос определяет пользователь. Примеры, предложенные до этого момента, подразумевали, что запрос был написан разработчиком и заранее известен. В некоторых случаях, вам может понадобиться, чтобы пользователь определил его/ее собственный запрос. В данном случае вы не будете знать число столбцов в выборке. Таким образом, вы можете использовать функцию sql_fetch_row() наряду с функцией count() для эффективной обработки столбцов.

<?php
for ($i = 0; $i < count($row); $i++) {
print "Column".($i + 1).$row[$i]."\n<BR>\n";
}
?>

Неверное использование SQL: Не Обрабатывается То Что Надо

Практика показывает, что неверно использовать PHP для обработки рядов во всей базе данных. Я встречал случаи, когда люди использовали PHP для проведения простого поиска по 2 MB базе данных, а потом удивлялись, почему язык настолько медленный. Обработка 2 MB данных займет вечность. Структуризированный Язык Запросов (SQL) был специально разработан для выборки данных из ваших таблиц. Идея в том, чтобы отфильтровать ненужные данные (используя SQL), оставив только релевантные набор данных, с которым мы будем работать (используя PHP). Если вы обрабатываете больше рядов, чем нужно, это верный признак, что SQL был использован не оптимально.

Параметр WHERE
Классический пример эффективного использования SQL это использование параметра where. Посмотрите на следующий пример, извлекающий выборку и выводящий имя и телефонный номер пользователя, когда он встречает ряд, где значение поля id равно 5:

<?php
//
// The connection is established and $conn is
// defined as the connection handle before this
// code.

$statement = "SELECT name, phone, id FROM samp_table";
$result = @sql_query($statement, $conn);

if (!$result) {
die (sprintf ("Error [%d]: %s",
sql_errno (), sql_error ()));
}

if (@sql_num_rows ($result) <= 0) {
die ("No results retrieved from Database");
}

while ($row = @sql_fetch_array ($result)) {
if ($row[id] == 5) {
print "Name: $row[name]\n<br>\n";
print "Phone: $row [phone]\n<br>\n";
break;
}
}
?>

Код выше не оптимизирован; мы используем PHP для поиска во всей базе данных! Хотя это и не особо значительно при работе с малыми базы данных, при увеличении объема вашей базы вы почувствуете значительное снижение скорости. Решение просто: измените свой SQL запрос так, чтобы он содержал параметр WHERE.

<?php
$statement = "SELECT name, phone FROM samp_table";
$statement .= " WHERE id='5'";
?>

Параметр where позволяет вам повысить селективность при выборе результатов из базы. Параметр where ограничивает количество элементов до удовлетворяющих аргументу. В предложенном выше примере аргументом был "id=5". Теперь, когда вы выбрали требуемым набор данных, можно использовать PHP для того, что просто вывести его:

<?php
if (@sql_num_rows ($result) != 1) {
die ("Incorrect number of results retrieved from DB");
}

$row = @sql_fetch_array ($result);
print "Name: $row[name]\n<br>\n";
print "Phone Number: $row[phone]\n<br>\n";
?>

Использование PHP для сортировки результатов

Многие люди запрашивают неотсортированную выборку, и рассчитывают использовать PHP для выполнения сортировки. Это просто напросто неэффективно, поскольку сортировка SQL гораздо эффективнее. Используйте параметр SQL order by вместо функции ksort(). Рассмотрим пример, использующий функцию ksort() для сортировки результата по имени:

<?php
$statement = "SELECT name, email, phone FROM some_table";
$statement .= " WHERE name IS LIKE '%baggins'";

$result = @sql_db_query ($statement, "samp_db", $conn);

if (!$result) {
die (sprintf ("Error [%d]: %s",
sql_errno (), sql_error ()));
}

while ($row = @sql_fetch_array ($result)) {
$matches[ $row[name] ] = array ($row[email],
$row[phone]);
}

ksort ($matches);
?>

Но почему не сортировать выборку в тот самый момент, когда мы ее запрашиваем? Это избавит нас от необходимости делать еще один проход по всему результату. Таким образом, уберите из примера выше функцию ksort() и замените SQL код на следующий, использующий параметр order by:

<?php
$statement = "SELECT name, email, phone FROM some_table";
$statement .= " WHERE name IS LIKE '%baggins'ORDER BY name";
?>

12. Отсутствие Проверок на Ошибки
Я выдел много программ, в которых нет нормальной проверки на ошибки. В основном это происходит из-за того, что программисты на тратят времени на планирование программы и на определение всех возможных мест, где что-нибудь может пойти неправильно. Проверка на ошибки нужно производить не после написания кода. Такое нежелание подумать о будущем может привести к критическим глюкам, которые не только выдадут неправильный результат, но и могу уронить всю вашу систему!

Ожидание худшего

У всех программ есть шанс перестать работать в "неверных" условиях. Чтобы уменьшить такую опасность, вы должны помнить:

Проверять результаты вызовов функций
Проверять результаты системных вызовов
Установить уровень error_level на E_ALL в файле php.ini
Проверять результаты вызовов функций

Когда вы вызываете функцию, возвращающую данные, с которыми нужно будет работать, всегда делайте проверку, что возвращаемые данные находятся в допустимых пределах. В примере ниже, ошибка деления на ноль возвращается при 6-ом проходе цикла for, поскольку $i уменьшается на один в то время, как $j увеличивается. На шестом проходе $i=$j=0.

<?php
mt_srand ((double) microtime () * 10000000);

function do_math ($a, $b)
{
return (($a - $b * 2) / mt_rand();
}

for ($i = 5, $j = -5; $i > -5; $i--, $j++) {
print $j / do_math ($i, $j) . "\n";
}
?>

Проверять результаты системных вызовов

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

<?php
$conn = @sql_connect ($host, $user, $pass);

if (!$conn) {
die (sprintf ("Error [%d]: %s",
sql_errno (), sql_error ()));
}
?>

Установите уровень error_reporting на E_ALL в файле php.ini

Обязательно настройте PHP так, чтобы она по максимуму сообщала обо всех возможных ошибках. Если вы не сделаете это хотя бы на время отладки, то можете пропустить такие ошибки, как неверные регулярные выражения и неправильные значения. Рассмотрите еще раз пример, который я привел для проверки результатов системных вызовов, показанный ниже. Предположим, что вы установили уровень отчета об ошибках в уровень ниже, скажем E_ERROR. Обратите внимание в примере ниже, что программа выполняет функцию do_math, но не сообщает о произошедшей ошибке деления на ноль (результата для случая $i=$j=0 не было).

<?php
error_reporting (E_ERROR);

mt_srand ((double) microtime() * 1000000);

function do_math ($a, $b)
{
return (($a - $b) * 2) / mt_rand();
}

for ($i = 5, $j = -5; $i > -5; $i--, $j++) {
print $j / do_math ($i, $j) . "\n";
}
?>

Пример работы:

-5148.25 -5271 -323.75 -4931 -7713.5 -4702.5 -488.5 -928.5 -1394.75
Свои Обработчики Ошибок

PHP обычно передает ошибки о выполнении броузеру, не позволяя вам подавить и отловить их. Однако, на PHP4 теперь можно отлавливать ошибки, используя функцию set_error_handler(). Функция set_error_handler() может быть использована для записи в лог ошибок, произошедших в вашей программе. Вместо того, чтобы беспокоить пользователя сообщениями об ошибке, вы можете сами отловить их, написав собственный обработчик ошибок. В примере ниже, set_error_handler() используется для создания функции error_handler() как обработчика ошибок по умолчанию. Каждый раз, когда случается ошибка, вызывается error_handler() и используется функция PHP error_log() для записи ошибки в файл error_file. Если это ошибка типа E_ERROR, мы прекращаем выполнение программы и выводим сообщение об ошибке.

<?php
// void error_handler(string type, string message, string file, int line)
// Custom error handler, set by the set_error_handler() function.

function error_handler ($type, $message, $file=__FILE__, $line=__LINE__)
{
error_log("$message, $file, $line", 3, 'error_file');

if ($type & E_ERROR) {
print 'An error occurred, it has been logged
and it will be addressed.';
exit;
}
}

set_error_handler('error_handler');
?>

11. Чрезмерное использование ОО
ОО - это замечательное понятие. У него есть множество преимуществ, самое значительное из которых - это легкое повторное использование кода в других задачах. Однако, все мы давно поняли: 'PHP не ОО язык'. Хотя в PHP есть адекватная поддержка объектной ориентированности, глупо и не эффективно использовать ОО методы, когда тех же результатов можно достичь другими способами. Причина этого заключается в том, что поддержка ОО в PHP очень слабая. Хотя большинство основных элементов присутствует, в PHP по прежнему нет некоторых наиболее продвинутых особенностей (таких, как protected private переменные члена), которые присутствуют в "настоящих" ОО языках (к примеру, в C++, Java). Кроме того, имеющийся код поддержки ОО в PHP не очень эффективен. Это означает, что использование ОО в PHP может на самом деле значительно замедлить выполнение ваших программ.

Примечание: В общем, приложение, использующее поддержку ОО окажется медленнее, также как использование eval() будет медленнее нормального кода. Чтобы пространно рассказать о местах, в которых поддержка ОО реализовано очень плохо, мне бы пришлось использовать расширенные особенности и концепции PHP, некоторые из которых еще не были описаны.

Что мы можем сделать без ОО?

Если вы пришли к PHP с такого языка, как Java или C++, в которых на самом деле нельзя написать достаточно сложную функцию без использования возможностей объектного ориентирования, вам может показаться сложным работать с PHP без поддержки ОО. Позвольте мне заверить вас, что даже очень мощные приложения можно написать без использования концепций и методов ОО (например, PHP был написан на C, не имеющего поддержки ОО). Для тех из вас, кто не привык работать без использование ОО, вот несколько различных способов создания способных к сцеплению и расширяемых приложений без использования ОО:

Создание API.
Создание порядка именования (и придерживание его).
Объединение функций в один файл.
Создание API

Добавьте три слоя с свою программу:

Во-первых, функции, которые на самом деле все делают.
Во-вторых, функции API. Это функции, которые вы используете для построения специфического приложения.
В-третьих, само приложение:
MortgageRate.php <?php
// The internal functions are layer 1

// Internal function to calculate the correct
// interest rate to be used given the amount per month
// and the time it is to be paid in

function _mort_find_interest_rate ($total)
{
if($total < 30000) return (7.4);
elseif($total > 30000) return (3.2);
elseif($total > 50000) return (2.5);
else return (1.7);
}

// The API is layer 2

// double calculate_mortgage_rate (int money, int time, int month)
// Calculate the mortgage rate given the
// the total money, time its paid over and
// the intervals

function calculate_mortgage_rate ($money, $time, $month)
{
$rate = _mort_find_interest_rate ($money) / 100;
$money /= ($time $month);
return ($rate * $money) + $money;
}

?> CalcMortgage.php <?php
// The actual application is layer 3

// $money, $time and $period are submitted from a form

include_once 'MortgageRate.php';

$price = calculate_mortgage_rate ($money, $time, $period);

print "Your $period month cost is $price";
?>

Создание порядка именования и придерживание его

Одна из основных проблем в любом большом проекте - это пересечение имен. Классы позволяют справиться с этим. Таким образом, в разных классах можно:

Назначить свойства с идентичными именами, или
Содержать методы с идентичными именами
К примеру, и у класса Philips, и у класса Normal могут быть одинаковые методы, названные "отвертка". В целом, до того, как начинать большой проект, вы должны определить порядок именования всего, способ отделения глобальных переменных от регулярных, способ определения библиотечных функций и т.д.

Объединение связанных понятий в один файл

Объединяйте похожие функции API в один файл также, как если бы объединяли похожие методы в класс. Постарайтесь думать о каждом файле, как о классе, а о каждой функции, как о методе. Таким образом, у ваших функций будут четкие определения и структура. К примеру, вы можете захотеть объединить все функции, связанные с доступом к базе данных в файл под названием DB.php.

ОО, как и все, хорошо в меру

Дайте мне кое-что объяснить. Я не пропагандирую полный отказ от объектно-ориентированных особенностей языка PHP. Скорее я просто пытаюсь предупредить вас, что не стоит использовать PHP, как Java или C++, где можно свободно использовать ОО. Внимательно взвесьте все плюсы и минусы до того, как решите применить объектно-ориентированный подход в PHP.

10. Неверное использование регулярных выражений.
Регулярные выражение - мощный инструмент для поиска и обработки данных, например проверки валидности адреса e-mail или URL. Тем не менее, они также медленнее, чем другие инструменты PHP, которые можно использовать для простых задач. К примеру, если вы хотите перевести всю строку в верхний регистр, вы может сделать следующее:

<?php
$URL = "http://www.php.net";

$fp = @fopen ($URL, "r");
if (!$fp) {
die ("Cannot open website $URL!");
}

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

@fclose ($fp)
or warn ("Cannot close website handle, $URL");

$data = ereg_replace ("[a-z]", "[A-Z]", $data);

print $data;
?>

Однако, вы увеличите время выполнения, используя медленную функцию ereg_replace() на то, что может сделать значительно более быстрая функция strtoupper().

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

Функции, которые вы должны знать

Существует набор функций, которые значительно сократят время выполнения скрипта при использовании их вместо регулярных выражений. Ниже приведен список этих "ценных" функций:
strtoupper(); strtolower(); ucfirst(); strtr(); str_replace(); trim(); explode(); implode(); substr(); strcmp();.

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

9. Программирование на PHP, Словно на Другом Языке
Многие люди начинают программировать на PHP после того, как станут опытными в таких языках, как Perl, C, Java или (о, ужас) ASP. Делая это, они используют методы программирования, которые не всегда подходят к методам, применяемым в PHP. К несчастью, некоторые такие люди не хотят потратить немного времени и научиться программировать на PHP так, как лучше это делать на нем. Вместо этого, они предпочитают использовать PHP, работая с наименьшим числом нововведений, насколько это возможно. Когда вы программируете на PHP, словно это какой-то другой язык, это часто приводит к замедленному и менее поддерживаемому коду. Часто можно определить, что человек программирует на PHP так, словно на другом языка, когда вы видите:

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

while () {
@_ = split /:/;
$quotes{shift} = shift;
}

print map { "$_: ", reverse split //,$quotes->{$_},"\n";
} keys %quotes

PHP

<?php
$fp = @fopen('php://stdin', 'r');
if (!$fp) {
die ('Cannot open STDIN');
}

while ($line = @fgets ($fp, 1024)) {
list($name, $quote) = explode (':', $line);
$quotes[$name] = $quote;
}

foreach ($quotes as $name => $quote) {
print "$name: ";
print implode (" ", array_reverse (preg_split ('//', $quote)));
print "\n";
}

@fclose ($fp);
?>

Пренебрежение встроенными функциями: Многие программисты на PHP, имеющим за плечами опыт работы на C, похоже не понимают, что у PHP есть множество встроенных функций, позволяющих избежать длинных кусков кода. Если вы пришли в PHP из C, я советую перед написание программы заглянуть в руководство по PHP и посмотреть, какие функции могут облегчить вашу жизнь.
Переименовывание существующих функций PHP: Я встречал пользователей, переименовывающих имеющиеся в PHP функции просто, чтобы им было легче их запомнить. Это не только замедляет скорость выполнения программы, но также снижает читабельность кода.
Чрезмерное употребление ОО: PHP не объектно-ориентированный язык, и, хотя и предоставляет такие возможности, вы всегда должны учесть, что использование их значительно замедлит ваши программы.
Где достать информацию

К счастью, есть множество мест, где можно узнать, как программировать на PHP, некоторые лучшие это:

Zend.com: Определенно. Вы ведь читаете эту статью, да??
Werad.narod.ru: И вы ведь читаете ее по-русски?
Professional PHP: Одна из лучших общих книг по PHP, подходит как программистам, так и нормальным людям.
Web Application Development with PHP: Отличная книга, раскрывающие концепции разработки веб-приложений, также как и некоторые крутые особенности PHP. Содержит официальную документацию Zend API.
The PHP Developer's Cookbook: Книга, описывающая решения распространенных проблем, с которыми сталкиваются множество разработчиков на PHP (Вышла в ноябре 2000 года, написана мной вместе с Андреем Змиевски).
8. Ненадежные Решения
Наши пользователи не всегда работают внутри наших систем. Наша задача как программистов - разработать надежную и прощающую ошибки пользователей систему.

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

К примеру, я видел скрипты, не использующие встроенную в PHP функцию mail(), достаточно надежную и безопасную. Вместо этого, скрипт передает e-mail пользователя sendmail'у, через popen(). Это может привести ко многим дырам в системе безопасности, (например, передаче /etc/passwd пользователю).

Вот некоторые места, в которых наиболее распространены дыры в системе безопасности или искажение данных:

При совершении системных вызовов. Я не могу в достаточно мере объяснить, насколько же это важно. Всегда проверяйте, что переданные пользователем данные безопасны перед передачей их в системный вызов. НИКОГДА СЛЕПО НЕ ДОВЕРЯЙТЕ ПОЛЬЗОВАТЕЛЮ И НЕ ПОМЕЩАЙТЕ ЕГО ДАННЫЕ В СИСТЕМНЫЙ ВЫЗОВ БЕЗ ПРОВЕРКИ.
При регистрации пользователей. Если вы хотите получить точные результаты, обязательно добавьте несколько проверку. Во-первых, убедитесь, что пользователь ввел валидный адрес e-mail. Далее, вы должны проверить, что возраст пользователя находится в допустимых пределах. В целом, можно исходить из того, что вокруг немного 200-летних стариков, способных пользоваться компьютером.
Принимая кредитные карточки. Некоторые программисты используют лишь простые алгоритмы, которые легко можно обмануть при проведении проверок кредитных карточек. Всегда связывайтесь с большой корпораций, чтобы проверить истинность номера кредитной карточки, прежде чем принять ее. НЕ ДОВЕРЯЙТЕ АЛГОРИТМУ.
Безопасность Системных Вызовов

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

Примечание: Обработка заключается в помещении обратного слеша \ перед символами, которые могут использоваться для обмана системы (#&;?'\"|*?~<>^()[]{}$\\x0A\xFF)

<html>
<head>
<title >Name Lookup </title>
</head>
<body>
<h1>Name Lookup</h1>
<?php
if ($name) {
system (EscapeShellCmd ("lookup $name"));
print "<br>\n\n";
}
?>
<form action="" method="GET">
Enter a name to lookup:
<input type="text" name="name">
<input type="submit" value="Lookup Name">
</form>
</body>
</html>

Примечание: Хотя EscapeShellCmd() достойная функция, чтобы убедиться что команда свободна от таких шуток, вы также должны произвести специальные проверки, зависящие от передаваемых данных. EscapeShellCmd() не проверяет валидность передаваемых данных, он просто не дает пользователю сделать что-то запрещенное.

На один шаг дальше

Как правило, легче проверять разрешенные, а не на запрещенные символы. К примеру, убедитесь что $name содержит лишь буквы и цифры. Таким образом снижается вероятность, что новоизобретенные способы уронить систему смогут пробраться через ваши фильтры.

Проверка адреса e-mail

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

>Проверка Сокета
Интерактивная Проверка
Проверка Сокета
Один способ проверки адреса e-mail без прямого привлечения к этому пользователя - это открыть сокет к серверу, указанному им и проверить такое имя пользователя.
Преимущества

Не причиняет неудобства пользователю.
Выявляет различные ложные адреса, которые бы не обнаружило регулярное выражение (например, joe@fhsdh.com)
Недостатки

Не отлавливает существующие, но чужие адреса. К примеру, если Вася Пупкин публикует мой адрес e-mail (sterling@php.net), сообщение будет обработано несмотря на то, что это мой адрес, а не его.
Работает медленнее регулярного выражения.
Почтовый сервер пользователя может временно не работать, что приведет к невозможности регистрации.
Интерактивная Проверка
Другой способ проверки адреса e-mail заключается в отправке специального "ключа" пользователю по почте, а затем в просьбе ввести этот специальный ключ для продолжения работы. Таким образом вы не только убеждаетесь в том, что данный почтовый ящик существует, но и в том, что у пользователя есть доступ к этому ящику.
Преимущества

Лучший способ убедиться, что пользователь ввел истинный адрес e-mail. (У них должен быть доступ к указанному адресу, чтобы завершить регистрацию)
Недостатки

Пользователь должен совершить дополнительные шаги, чтобы совершить регистрацию. Они будут во всем винить вас.
Как и любой способ, нет защиты от дурака. Пользователь может создать временный ящик на hotmail или netaddress и использовать его для регистрации на вашем сайте.
Обобщение
В этой статье мы обсудили второй набор ошибок, серьезных ошибок с №14 до 8, совершаемых программистами при написании PHP. Эти серьезные ошибки:

Не следование правилам именования: Следование правилам именования приведет к более понятному и поддерживаемому коду
Не продумано: Базы Данных SQL: Неправильная обработка данных - хороший пример невнимательного программирования. Некоторые программисты не тратят время на то, чтобы все внимательно обдумать. Да, может есть не один "правильный" способ обработки данных, но неправильных - гораздо больше.
Отсутствие проверок на ошибки: Обязательно нужно выделить время и вставить проверку на ошибки в свою программу. Особое внимание уделите проверке результатов вызовов функций и системных вызовов.
Чрезмерное использование ОО: Поскольку PHP не полноценный объектно-ориентированный язык, не надо использовать его ОО возможности так свободно, как в языках C++, Java (или даже Perl).
Неверное использование регулярных выражений: Регулярные выражения медленные. Когда планируете использовать регулярное выражение, сначала убедитесь, что нет более простой и быстрой функции, с помощью которой вы достигните тех же результатов.
Программирование на PHP, словно на другом языке: Вы не должны программировать на PHP, словно на Perl или C. PHP отдельный язык сам по себе. Таким образом, вы должны научиться правильно писать на PHP, а не делать все так, как вы бы сделали на другом языке.
Ненадежные решения: При разработке системы всегда принимайте во внимание человеческие ошибки. Никогда не помещайте переданные пользователем данные в системный вызов без предварительной проверки. Проверяйте адрес электронной почты. Не доверяйте алгоритмам при приеме кредитной карточки.
Категория: Статьи о PHP | Добавил: Rammstein (08.12.2010)
Просмотров: 787 | Рейтинг: 0.0/0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Реклама
Поиск
Друзья сайта
Топ100- Веб-дизайн free counters