Статьи

Статический анализ с помощью PHPSA: PHP Smart Analyzer

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

Хороший способ замедлить это увеличение сложности — использовать инструменты статического анализа. Статический анализ — это процесс анализа программного обеспечения без его фактического выполнения — своего рода автоматический просмотр кода. Инструменты статического анализа будут обнаруживать распространенные ошибки, обеспечивать соблюдение стандартов кодирования и даже очищать блоки кода. Дни имени php -l filename еще не закончились, но теперь у нас есть ряд отличных инструментов, которые помогают нам создавать и поддерживать высококачественный код.

Что касается php -l filename , старого доброго PHP-кода, это то, что будет выполнять синтаксический анализ целевого файла и выводить любые найденные ошибки. Раньше у меня был маленький кусочек кода, который я использовал для отправки писем с помощью PHP. Это хорошая отправная точка для нашего анализа.

 <?php class Email{ //Constructor function Email( $subject, $message, $senderName, $senderEmail, $toList, $ccList=0, $bccList=0, $replyTo=0 ){ $this->sender = $senderName . " <$senderEmail>"; $this->replyTo = $replyTo; $this->subject = $subject; $this->message = $message; // Set the To recipients if( is_array($toList)){ $this->to = join( $toList, "," ); }else{ $this->to = $toList; } // Set the cc list if( is_array($ccList) && sizeof($ccList)){ $this->cc = join( $ccList, "," ); }else{ $this->cc = $ccList; } // Set the bcc list if( is_array($bccList) && sizeof($bccList)){ $this->bcc = join( $bccList, "," ); }else{ $this->bcc = $bccList; } } function sendMail(){ //create the headers for PHP mail() function $this->headers = "From: " . $this->sender . "\n"; if( $this->replyTo ){ $this->headers .= "Reply-To: " . $this->replyTo . "\n"; } if( $this->cc ){ $this->headers .= "Cc: " . $this->cc . "\n"; } if( $this->bcc ){ $this->headers .= "Bcc: " . $this->bcc . "\n"; } print "To: " . $this->to ."<br>Subject: " . $this->subject . "<br>Message: " . $this->message . "<br>Headers: " . $this->headers; return mail( $this->to, $this->subject, $this->message, $this->headers ); } } 

Как видите, это простой класс для отправки электронной почты. Если мы запустим наш PHP Lint
по этому коду мы увидим, что все хорошо.

 php -l Email.php 

Результат следующий:

No syntax errors detected in Email.php

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

Введите PHP Smart Analyzer

Затерянный в статике

PHPSA — это инструмент статического анализа для PHP.

PHPSA может быть установлен как .phar или через Composer , например так:

 composer require ovr/phpsa 

Это создаст утилиту командной строки, которая будет связана с папкой vendor/bin нашего проекта.

Использование PHPSA

После завершения установки мы можем запустить ./vendor/bin/phpsa .

Варианты PHPSA

Результат, который мы получаем после выполнения вышеприведенного, совпадает с результатом выполнения команды list . Команда help выведет список инструкций по запуску справки в PHPSA. Команда check выполнит статический анализ для указанного файла или папки.

Поскольку мы запускали PHP-код раньше, ожидается, что PHPSA не найдет никаких синтаксических ошибок в нашем коде. Но что произойдет, если мы специально вставим ошибку? Сможет ли PHPSA его найти?

Давайте сделаем небольшое изменение в нашем классе электронной почты.

 <?php class Email{ //Constructor function Email( $subject, $message, $senderName, $senderEmail, $toList, $ccList=0, $bccList=0, $replyTo=0 ){ $this->sender = $senderName . " <$senderEmail>"; $this->replyTo = $replyTo; $this->subject = $subject; $this->message = $message; // Set the To recipients if( is_array($toList)){ $this->to = join( $toList, "," ); }else{ $this->to = $toList; } // Set the cc list if( is_array($ccList) && sizeof($ccList)){ $this->cc = join( $ccList, "," ) }else{ $this->cc = $ccList; } // Set the bcc list if( is_array($bccList) && sizeof($bccList)){ $this->bcc = join( $bccList, "," ); }else{ $this->bcc = $bccList; } } function sendMail(){ //create the headers for PHP mail() function $this->headers = "From: " . $this->sender . "\n"; if( $this->replyTo ){ $this->headers .= "Reply-To: " . $this->replyTo . "\n"; } if( $this->cc ){ $this->headers .= "Cc: " . $this->cc . "\n"; } if( $this->bcc ){ $this->headers .= "Bcc: " . $this->bcc . "\n"; } print "To: " . $this->to ."<br>Subject: " . $this->subject . "<br>Message: " . $this->message . "<br>Headers: " . $this->headers; return mail( $this->to, $this->subject, $this->message, $this->headers ); } } 

На этот раз в нашем коде есть явная синтаксическая ошибка. Давайте запустим PHPSA и проверим результаты.

Синтаксические ошибки PHPSA

Как мы видим, PHPSA быстро обнаруживает синтаксическую ошибку. Но на самом деле все это не ново, наш простой PHP-скрипт тоже может обнаружить эту ошибку. Итак, давайте исправим это и проверим, что еще PHPSA готовит для нас.

PHPSA статический анализ

Много на что посмотреть сейчас!

 Notice: Missing docblock for Email() method in src/Email.php on 6 [missing-docblock] Notice: join() is an alias of function. Use implode(...). in src/Email.php on 15 [fcall.alias] Notice: sizeof() is an alias of function. Use count(...). in src/Email.php on 21 [fcall.alias] Notice: Property sender does not exist in Email scope in src/Email.php on 38 [undefined-property] 

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

Давайте исправим наш код, чтобы исправить все вышеперечисленное.

 <?php /** * Simple email sender class * */ class Email { /** * The email headers */ var $headers; /** * The email sender */ var $sender; /** * The email recipients */ var $to; /** * Reply To */ var $replyTo; /** * Email cc list */ var $cc; /** * Email bcc list */ var $bcc; /** * Email content */ var $message; /** * The subject of the email */ var $subject; /** * This is the constructor for the Email class */ function Email( $subject, $message, $senderName, $senderEmail, $toList, $ccList = 0, $bccList = 0, $replyTo = 0 ) { $this->sender = $senderName . " <$senderEmail>"; $this->replyTo = $replyTo; $this->subject = $subject; $this->message = $message; // Set the To recipients if (is_array($toList)) { $this->to = implode($toList, ","); } else { $this->to = $toList; } // Set the cc list if (is_array($ccList) && count($ccList)) { $this->cc = implode($ccList, ","); } else { $this->cc = $ccList; } // Set the bcc list if (is_array($bccList) && count($bccList)) { $this->bcc = implode($bccList, ","); } else { $this->bcc = $bccList; } } /** * The function that actually sends the email * * @return boolean Returns TRUE if the mail was successfully accepted for delivery, FALSE otherwise. */ function sendMail() { //create the headers for PHP mail() function $this->headers = "From: " . $this->sender . "\n"; if ($this->replyTo) { $this->headers .= "Reply-To: " . $this->replyTo . "\n"; } if ($this->cc) { $this->headers .= "Cc: " . $this->cc . "\n"; } if ($this->bcc) { $this->headers .= "Bcc: " . $this->bcc . "\n"; } print "To: " . $this->to . "<br>Subject: " . $this->subject . "<br>Message: " . $this->message . "<br>Headers: " . $this->headers; return mail($this->to, $this->subject, $this->message, $this->headers); } } при <?php /** * Simple email sender class * */ class Email { /** * The email headers */ var $headers; /** * The email sender */ var $sender; /** * The email recipients */ var $to; /** * Reply To */ var $replyTo; /** * Email cc list */ var $cc; /** * Email bcc list */ var $bcc; /** * Email content */ var $message; /** * The subject of the email */ var $subject; /** * This is the constructor for the Email class */ function Email( $subject, $message, $senderName, $senderEmail, $toList, $ccList = 0, $bccList = 0, $replyTo = 0 ) { $this->sender = $senderName . " <$senderEmail>"; $this->replyTo = $replyTo; $this->subject = $subject; $this->message = $message; // Set the To recipients if (is_array($toList)) { $this->to = implode($toList, ","); } else { $this->to = $toList; } // Set the cc list if (is_array($ccList) && count($ccList)) { $this->cc = implode($ccList, ","); } else { $this->cc = $ccList; } // Set the bcc list if (is_array($bccList) && count($bccList)) { $this->bcc = implode($bccList, ","); } else { $this->bcc = $bccList; } } /** * The function that actually sends the email * * @return boolean Returns TRUE if the mail was successfully accepted for delivery, FALSE otherwise. */ function sendMail() { //create the headers for PHP mail() function $this->headers = "From: " . $this->sender . "\n"; if ($this->replyTo) { $this->headers .= "Reply-To: " . $this->replyTo . "\n"; } if ($this->cc) { $this->headers .= "Cc: " . $this->cc . "\n"; } if ($this->bcc) { $this->headers .= "Bcc: " . $this->bcc . "\n"; } print "To: " . $this->to . "<br>Subject: " . $this->subject . "<br>Message: " . $this->message . "<br>Headers: " . $this->headers; return mail($this->to, $this->subject, $this->message, $this->headers); } } 

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

Вывод

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

Статический анализ является ценным инструментом, если мы хотим обеспечить соблюдение стандартов качества в наших базах кода. Это становится еще более ценным при работе в команде, так как заставляет всех использовать одни и те же стандарты. Несмотря на то, что он все еще немного отстает от некоторых других инструментов, таких как Code Sniffer или Mess Detector , PHPSA — очень полезный инструмент, который демонстрирует большие перспективы. Поскольку одним из лучших способов охвата более широкого диапазона ошибок является комбинирование различных инструментов анализа, рассмотрите возможность использования PHPSA в своем стеке QA. Не забудьте взять его на заметку и, возможно, внести свой вклад в проект на github, где перечислены различные задачи и запланированные функции.

Вы уже пробовали PHPSA? Дайте нам знать, как вы себя чувствуете по сравнению с остальными!