PHP 함수 타입 선언과 정적분석도구 phan 활용하기

421 words

PHP에서도 다른 타입 언어처럼 함수 인자에 타입을 지정할 수 있도록 타입 선언(Type declaration)을 지원한다. 1 동적 타입 언어에서 왜 이런 문법을 사용해야 하는가에 대한 이야기는 여전히 많지만 타입 선언을 사용하는 쪽을 선호한다. TDD를 충실히 한다면 함수에서의 타입 선언이 의미 없다고 생각할 수 있겠지만 여전히 얻을 수 있는 장점도 많기 때문이다. 그 장점 중 하나로 정적 분석을 들 수 있다.

예제

컴파일을 수행하는 언어에서는 이 정적 분석을 통과하지 못하면 컴파일이 되지 않아 실행조차 할 수 없다. 하지만 PHP는 스크립트 언어로 별도의 컴파일 없이 실행할 수 있다. 아래 코드에서는 인터페이스에 선언되지 않은 메소드를 호출하고 있다. 정상적으로 실행이 될까?

<?php
interface FoodInterface
{
}
class FriedChicken implements FoodInterface
{
    public function getName()
    {
        return self::class;
    }
}
class Human
{
    public function eat(FoodInterface $food)
    {
        echo $food->getName();
    }
}

이제 이 코드를 실행해보자.

<?php
$chicken = new FriedChicken;
$me = new Human;
$me->eat($chicken);

위 코드를 php에서 실행하면 FriedChicken이 출력되는 것을 볼 수 있다. 즉, FoodInterfacegetName() 메서드가 선언되어 있지 않더라도 이 메서드를 호출하는 것이 가능하다. 이런 경우라면 getName()가 없지만 FoodInterface를 구현한 다른 인스턴스라면 분명 문제가 생긴다. PHP는 여전히 동적 타입 특성을 갖고 있기 때문에 이런 문제를 해결하기 어렵다.

class Human
{
    public function eat(FoodInterface $food)
    {
        // 타입 선언을 했는데도 덕타이핑을 하는 것은 이상함
        if (!method_exists($food, 'getName')) {
            throw InvalidArgumentException();
        }
        echo $food->getName();
    }
}

여기서는 코드 규모가 작고 간단한 테스트 코드를 작성했기 때문에 쉽게 확인할 수 있었다. 즉, 정적 분석 없이도 테스트를 잘 작성한다면 문제가 없겠지만 제대로 테스트가 작성되어 있지 않거나 코드의 규모가 큰 경우에는 이런 문제를 빠르게 검출하기 어렵다.

이런 상황에서 코드를 실행하지 않고도 문제를 찾기 위해 etsy/phan을 사용할 수 있다.

phan 사용하기

이 패키지는 php-ast 확장을 추가로 요구한다. 맥 또는 리눅스 환경은 리포지터리를 받아 phpize를 통해 간단히 설치할 수 있고 윈도 환경은 미리 컴파일 된 ast.dll을 받아 설치하면 된다. php.ini를 수정하는 것을 잊지 말자.

$ brew install php71
$ git clone https://github.com/nikic/php-ast.git
$ cd php-ast
$ phpize
$ ./configure
$ make install

그리고 사용할 패키지에 phan을 추가한다.

$ composer require --dev etsy/phan
$ vendor/bin/phan --help

phpcs를 사용해본 경험이 있다면 크게 다르지 않게 사용할 수 있다.

$ vendor/bin/phan -l src
src/foodie.php:18 PhanUndeclaredMethod Call to undeclared method \FoodInterface::getName

인터페이스에 정의되지 않은 getName을 호출했다는 사실을 확인 가능하다.


개발 환경에서의 이런 문제는 제대로 된 IDE(e.g. PHPStorm)를 사용한다면 미리 발견할 수 있다. CI/CD을 하고 있다면 phan을 중간에 추가하는 것도 좋은 아이디어다.


  1. 타입 힌트(Type hint)는 php5에서 사용된 명칭이다. 
haruair

사소한 이야기를 많이 나누고 싶어하는 해커. 티끌 같은 기술들이 세상을 바꾼다고 믿습니다.

One response to “PHP 함수 타입 선언과 정적분석도구 phan 활용하기

Leave a Reply