Пять моих «граблей» в разработке на PHP

Содержание

Здравствуйте, уважаемые пользователи! В этом посте хотел бы поделиться своим личным опытом «наступления на грабли» во время разработки веб-приложений на языке программирования PHP. Текст будет интересен тем, кто хочет посмотреть на путь девелопера от «зеленого самоучки» до «профессионального разработчика», а также начинающим программистам, которые не против узнать о том, «как не нужно делать» и почему. Возможно даже кто-то вспомнит себя и улыбнётся. Возможно, кто-то просто улыбнётся с моего старого кода.

Пять моих «граблей» в разработке на PHP

Все мое ознакомление с веб-разработкой начиналось в далеком 2009-м году с распечатанных непонятных и сложных справочников и руководств, а также ковыряния кода (очень плохого, кстати) open source CMS. Позже я начал использовать ООП и заботиться о «правильности», а ещё позже — замечательный фреймворк Yii, поэтому весь «хороший» код в посте будет демонстрироваться именно с использованием этого фреймворка.

1. Дублирование кода

Сейчас, смотря на свой код минувших лет, я понимаю, что это были действительно ужасные времена. У меня дублировалось практически всё. Функции писались редко, а один и тот же код можно было увидеть в трех-четырех (а то и больше) местах. Почему я так делал? Ну естественно потому что я был неопытным. Это раз. И потому что считал (глупо считал), что написание функции — это трата времени и что гораздо проще просто cкопировать одно и тоже несколько раз.

Что было раньше:

$sql = 'SELECT `id` FROM `days` WHERE `sta`=1';
$r=mysql_query($sql,$conn);
$row=mysql_fetch_row($r);

$curday=$row[0];

if (($curday>=3 && $curday<=15) || ($curday>=45 && $curday<=55) || ($curday>=90 && $curday<=105))
    {
           $on_off=1;
    }else{
           $on_off=0;
    }

Что есть сейчас:

$curDay = BasicFunctions::getCurrentDay();
            $transferStatus = BasicFunctions::getTransferStatus($curDay);

            if ($transferStatus == 1) {
               ...
            }

Позже я понял, зачем делать «хорошо»:

Самая важная причина создания метода — снижение сложности программы. Методы создаются для того, чтобы можно было скрыть информацию и не думать о ней. Другие причины создания методов — минимизация объема кода, облегчение сопровождения программы и снижение числа ошибок.

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

2. Пересекание PHP и HTML

Да, я не использовал патернов проектирования. Да, я не использовал популярногоMVC. И это было второй моей фатальной ошибкой. Почему я так делал? Я почему-то не думал о том, что код когда-то может быть переписан/дописан/изменен. Всё «хардкорилось» чисто с расчетом на сиюминутную выгоду.

Что было раньше:

echo '<br /><br /><center><img src="img/cap.jpeg" alt="Капитан" title="Капитан"> <b>Капитан</b></center>';

              $sql = 'SELECT * FROM `capitans` WHERE `club`='.$_SESSION['my_club'];
               $r=mysql_query($sql,$conn);
               $row=mysql_fetch_row($r);    $idp=$row[2];

if (!isset($row[2]) || $row[2]=="")
   {
   echo '<center>Капитан команды не назначен</center><br>';
   }else{

              $sql = 'SELECT * FROM `players` WHERE `id`='.$idp;
               $r=mysql_query($sql,$conn);
           $row=mysql_fetch_row($r);

     ....

}

Что есть сейчас:

$capitan = Capitans::model()->findByAttributes(array('club' => $user->club));

            $this->render('team', array(
                ...
                'capitan' => $capitan,
                ...
            ));

----------------------------------------

<?php if ($capitan == $item->pl_id) {  ?>
   <i class="cap" title="Капитан" alt="Капитан"></i>
<?php } ?>

Позже я понял, зачем делать «хорошо»:

Использования паттерна проектирования (при веб-разработке чаще всего это MVC) снижает сложность разработки за счёт готовых абстракций для решения целого ряда проблем. Например, логические части приложения разделяются на автономные области. Например, в том же MVC модель данных, пользовательский интерфейс и взаимодействие с пользователем разделены на три отдельных компонента. Зачем? Затем, чтобы модификация одного из компонентов оказывала минимальное воздействие на остальные.

3. Не использование фреймворка

Я года два писал всё сам и не использовал фреймворков. Я считал, что это что-то очень сложное и на изучение «этого» у меня нет времени. Есть люди, которые принципиально не используют фреймворки, например, потому что они считают, что фреймворк — это open source, который доступен каждому (т. е. каждый может просмотреть его код и найти узкие места). Эти люди, которые так считают, пишут свои фреймворки, которые используют в следующих проектах. Лично я считаю, что сейчас есть TOP-3 (или TOP-5) тех фреймворков, которые проверены на популярных проектах и отточены до максимума, поэтому резон писать что-то свое стремится к нулю. Если вы так не считаете, проголосуйте в конце поста.

Что было раньше (авторизация):

if (!isset($_POST['login']) || strlen($_POST['login'])<3)
{
    $errorsArray[] = 'Не введён логин или он слишком короткий';
    $sum=$sum+1;
}
if (!isset($_POST['pass']) || strlen($_POST['pass'])<3)
{
    $errorsArray[] = 'Не введён пароль или он слишком короткий';
    $sum=$sum+1;
}
if (!preg_match("/^([a-zA-Z0-9]+)$/", $_POST['login']))
{
    $errorsArray[] = 'В поле "логин" присутствуют недопустимые символы';
    $sum=$sum+1;
}
if (!preg_match("/^([a-zA-Z0-9]+)$/", $_POST['pass']))
{
    $errorsArray[] = 'В поле "пароль" присутствуют недопустимые символы';
    $sum=$sum+1;
}

$sql = 'SELECT * FROM `users` WHERE `login`="'.$_POST['login'].'"';
$r=mysql_query($sql,$conn);
$row=mysql_fetch_row($r);

if ($row[1]!==$_POST['login'] || $row[2]!==md5($_POST['pass']))
{
    $errorsArray[] = 'Неверный логин или пароль';
    $sum=$sum+1;
}

Что есть сейчас (авторизация):

public function actionLogin()
    {
        $model=new LoginForm;

        if(isset($_POST['LoginForm']))
        {
            $model->attributes=$_POST['LoginForm'];
            // validate user input and redirect to the previous page if valid
            if($model->validate() && $model->login())
                $this->redirect(Yii::app()->user->returnUrl);
        }
        // render form
        $this->render('login',array('model'=>$model));
    }

Позже я понял, зачем нужно использовать фреймворк:

Любой фреймворк — это, в первую очередь, набор уже готовых к использованию стандартов, которые используют, тратя намного меньше времени, разработчики. Кроме этого, вокруг популярных open sourse фреймворков собирается серьезное сообщество разработчиков. Что это значит? А это значит то, что будет легко подключить или заменить человека в команде работающей над проектом. Плюс, комьюнити создает массу готовых сторонних решений.

4. Классы? Не, не слышал

Классы не использовались вообще. Хотя, при описанных выше «ляпах», о каких классах может идти речь :)

Что было раньше:

include_once("inc.php");
include_once("head.php");
include_once("system.php");

if (isset($_SESSION['login']) && isset($_SESSION['password']))
   {

  if (!isset($_GET['id']) || $_GET['id']=="")
     {

       ...

     }
   }

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

/**
 * Class BasicFunctions
 * Same functions for all controllers
 */
class BasicFunctions {
   ...

    /**
     * Get info about last registered users
     * @ param type $limit - limit
     * @ return array - users
     */
    public static function getLastRegUsers ($limit) {
           $criteria=new CDbCriteria;
           $criteria->limit = $limit;
           $criteria->order = 'user_id DESC';
           $users = Users::model()->findAll($criteria);

           return $users;        
    }

   ...

}

Позже я понял, зачем делать «хорошо»:

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

5. Не использование LIMIT’ов, JOIN’ов, запросы в циклах

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

Что было раньше (случайный код):

$sqlo = 'SELECT `id`, `pos` FROM `players`';
               $ro=mysql_query($sqlo);
           while($rowo=mysql_fetch_row($ro))
        {
if ((int)$rowo[0]==(int)$ex2[0]){

$r_tmp_2 = mysql_query("SELECT `pos` FROM `pos` WHERE `id`=".$rowo[1]."");
$row_tmp_2=mysql_fetch_row($r_tmp_2);

            ...

                }
        }

Что есть сейчас (случайный код):

if ($addNewBuild = Yii::app()->request->getQuery('addNewBuild')) {
                $building = Buildings::model()->findByPk($addNewBuild); // Ищем первую запись по Primary Key и возвращаем её, если она найдена
                if ($building) {
                   ...
                }else{
                  ...
                }
           }

Позже я понял, зачем делать «хорошо»:

Вы должны заботиться о быстродействии своих приложений. Вы должны заботиться о правильности написания SQL-запросов. Именно SQL-запросы составляют большую часть приложения и именно они в основном влияют на быстродействие. Использование LIMIT’ов помогает избежать проходов по всем записям таблицы, а использование JOIN’ов помогает избежать циклических запросов.

Вот такая вот история. Всем спасибо за интерес, внимание, и улыбки (надеюсь, они у вас были). Если вам этот пост понравился, в следующем расскажу о том, как я «вышел» на фреймворки и на Yii в частности.