Statyczna analiza kodu PHP z Phan

Tomasz Tybulewicz / @tybulewicz

Historia

https://twitter.com/rasmus/status/532288201852198912
https://twitter.com/rasmus/status/616740838102532097
https://twitter.com/rasmus/status/671836218896736257

obecnie rozwijany w Etsy

większość zmian autorstwa Andrew Morrisona

Działanie

Wymagania

  • wymaga PHP 7 i rozszerzenia php-ast
  • analizuje kod dowolnej wersji PHP

Przykłady łapanych błędów


function getNumber(): int
{
}
// Method \getnumber is declared to return int but has no return value
                

function tailParametersRequired($p1 = null, $p2)
{
}
// Required argument follows optional
                        

function oneParameter($i)
{
}
oneParameter(1, 2);
// Call with 2 arg(s) to \oneparameter() which only takes 1 arg(s)
                        

$arr = false;
if ($arr[1]) {
}
// Suspicious array access to bool
                        

if (42 == [13, 37]) {
}
// int to array comparison

if ([13, 37] == 'string') {
}
// array to string comparison
                        

$v = null;
if ($v instanceof Undef) {
}
// Checking instanceof against undeclared class \undef
                        

/**
 * @return int
 */
function voidReturn() {
    return null;
}
// Returning type null but voidreturn() is declared to return int
                        

/**
 * @return int[]
 */
function oldComment() {
    return ['to be or not to be'];
}
// Returning type string[] but oldComment() is declared to return int[]
                        

Moje doświadczenia

Trudne początki

PHAN się wysypywał przy analizie Wordpressa

Pomogło cofnięcie wersji do release 0.2

Master został szybko poprawiony

Błędy związane z klasami z rozszerzeń


Property of undeclared type \memcached
Call to method get from undeclared class \memcached
                            

Moje PHP 7 nie miało wkompilowanego tego rozszerzenia, dodałem do analizy plik "nagłówkowy" z definicją interface'u.

Błędy z rozpoznawaniem przestrzeni nazw


PhanSignatureMismatch Declaration of function
buildForm(\symfony\component\form\formbuilderinterface $builder, array $options) should be compatible with function
buildForm(\Symfony\Component\Form\formbuilderinterface $builder, array $options)
                    

Problem poprawiony w 1h od zgłoszenia

Domyślny plik konfiguracyjny

.phan/config.php

Przykładowa konfiguracja Phan:
github.com/etsy/phan/blob/master/.phan/config.php

Pełen plik:
github.com/etsy/phan/blob/master/src/Phan/Config.php

pierwsza próba


'directory_list' => [
    'src',
    'vendor',
],
'exclude_analysis_directory_list' => [
    'vendor/'
],
                        

pierwsza próba

  • czas analizy > 30s
  • użyta pamięć > 2GB

obecnie


'file_list' => [
    'app/AppKernel.php',
    'vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php',
    // 87 innych plików z vendor
    'vendor/symfony/symfony/src/Symfony/Component/Yaml/Yaml.php',
],
'directory_list' => [
    'src',
],
'exclude_analysis_directory_list' => [
    'vendor/',
],
                        

obecnie

  • czas analizy < 2s
  • użyta pamięć - pomijalnie mało

Użycie w naszym projekcie

  • testy u mnie: 1,5 miesiąca
  • reszta zespołu: 2 tygodnie
  • CI: planujemy od wersji 1.0

Użycie w Etsy

  • od tygodnia (info z 19 lutego) działa produkcyjnie
  • blokuje deploymenty w przypadku wykrycia błędów

Podsumowanie

Plusy

  • aktywnie rozwijany
  • "oryginalne" AST
  • wykrywa problemy pomijane przez inne narzędzia
  • analizuje PhpDoc
  • dobry kontakt z developerami

Minusy

  • aktywnie rozwijany
  • wersja z gałęzi master często nie działa
  • false positives
  • nie zgłasza problemów z @throws
  • dość nowy projekt - mało informacji w sieci

Minusy

Zastosowanie

  • kolejne narzędzie do analizy kodu
  • wykrywa błędy zanim staną się problemem
  • wspiera podczas przeglądu kodu

Linki

Pytania?

używałem Phan zanim to było modne

Tomasz Tybulewicz / @tybulewicz