PHP 5.1 부터 -a 옵션을 통해 대화형으로 PHP 인터프리터를 실행할 수 있으므로 간단하게 특정 기능의 동작을 확인하고 싶을 경우 사용할 수 있습니다. 

PHP 대화형 인터프리터

$ php -a
Interactive mode enabled


php > $str='Hello World';
php > var_dump($str);
string(11) "Hello World"
BASH

하지만 라라벨같이 복잡한 프레임워크나 혹은 외부 라이브러리를 사용하는 로직을 테스트할 경우 많은 설정이 필요하므로 PHP 에 내장된 대화형 인터프리터는 유용하지 않습니다.


대화형으로 코드를 실행하는 인터프리터보다 더욱 진보된 방식의 처리기를 REPL(Read–eval–print loop) 이라고 부르며 이름처럼 사용자의 입력을 받고 이를 처리하고 결과를 출력하는 루프를 실행합니다.

라라벨 5부터는 PHP 의 REPL 구현물중 Psysh(www.psysh.org) 라는 프로젝트를 내장하여 REPL 을 제공하고 있으며 artisan tinker 명령어를 통해 접근할 수 있고 다음과 같은 경우에 유용하게 사용할 수 있습니다.

  • 간단한 로직을 테스트하거나 구현전에 아이디어를 확인
  • 단위 테스트를 만들기 애매한 작은 단위 코드 테스트
  • 특정 조건에서만 실행되는 코드를 테스트

그러면 Task 클래스를 tinker 명령어를 통해서 사용해 보겠습니다

$ php artisan tinker
 
Psy Shell v0.4.4 (PHP 5.6.6-1+deb.sury.org~utopic+1 — cli) by Justin Hileman
>>> 
BASH

REPL 프롬프트(>>>) 에 실행할 PHP 구문을 입력하면 되며 처리한 결과의 리턴값은 => 를 통해 출력됩니다. 먼저 모델 클래스 객체를 생성해 보겠습니다.

>>> $t = new App\Task 
=> <App\Task #000000000da496f00000000002502907> {}
PHP

새로운 Task 객체를 생성하고 이를 $t 라는 변수에 할당하는 구문을 입력하였고 REPL 은 이를 읽고 처리(Task 객체 생성)후 결과로 객체의 주소를 출력하고 다시 프롬프트 표시하고 있습니다.


이제 객체의 프로퍼티에 값을 할당해 보겠습니다. 모델 클래스는 오버로딩(REF: PHP의 오버로딩 항목 참고) 을 사용하여 동적으로 프로퍼티를 생성하므로 모델 클래스에 만들어 줄 필요가 없습니다.

>>> $t->name = 'Laravel 5 Programming'
=> "Laravel 5 Programming"
PHP

이제 프로퍼티에 설정된 값을 출력하기 위해 dump 함수를 사용해 봅시다.

dump 는 Symphony 프레임워크의 VarDumper 패키지의 함수로 var_dump 보다 가독성 좋은 결과를 출력해 주주므로 var_dump 대신 dump() 를 사용하는 게 좋습니다.

또는 객체의 정보를 출력하고 이후의 실행을 종료하는 라라벨의 헬퍼 함수인 dd() 도 디버깅시에 유용합니다.

>>> dump($t->name)
"Laravel 5 Programming"
=> null
PHP


이제 DateTime 을 처리하는 PHP 의 유명한 라이브러리인 카본(Carbon) 을 사용하여 tinker 에서 DateTime 을 처리하는 예제를 학습해 보겠습니다.

현재 시간을 얻어 오는 Carbon::now()  메소드를 사용하여 현재 시간을 $dt 라는 변수에 저장해 보겠습니다.

>>> $dt = \Carbon\Carbon::now()
=> <Carbon\Carbon #0000000022ada689000000007004bfb4> {
       date: "2015-06-01 00:22:52.000000",
       timezone_type: 3,
       timezone: "Asia/Seoul"
   }
PHP

카본은 날자를 다룰 수 있는 여러 가지 메소드를 제공하고 있습니다. 그중에 addMonths, addDays 를 사용하여 현재 일로부터 3달 37 일 후는 언제인지 계산해 보겠습니다.

>>> $dt->addMonths(3)->addDays(37)
=> <Carbon\Carbon #0000000022ada6fb000000007004bfb4> {
       date: "2015-10-08 00:33:46.000000",
       timezone_type: 3,
       timezone: "Asia/Seoul"
   }
CODE

라라벨은 카본 라이브러리에 의존성이 있으므로 composer로 라라벨 프로젝트를 생성하면 카본 라이브러리도 자동으로 vendor 폴더에 설치가 됩니다.


tinker 는 라라벨의 모든 기능을 사용할 수 있으므로 view 헬퍼를 통해 뷰 클래스도 생성할 수 있습니다. 전 장에서 만든 레이아웃 뷰인 task.list3.blade.php 를 생성하고 데이타가 어떻게 전달되었는지 확인해 보겠습니다.

먼저 view 헬퍼 함수로  page 뷰를 생성하고 데이타를 전달합니다

>>> $v = view('task.list3')->with('tasks', ['name'=>'Task 1', 'due_date'=> '2015-06-01'])
=> <Illuminate\View\View #00000000593636e70000000035f9538c> {}
PHP

생성된 $v 변수는 어떤 클래스 타입인지 알아 보기 위해 PHP 의 get_class 함수로 타입을 출력합니다. view 헬퍼로 생성된 객체는 라라벨의 View 클래스인 것을 알 수 있습니다.
>>> get_class($v)  
=> "Illuminate\\View\\View"
PHP

tinker 는 bash 쉘의 readline 기능을 지원하므로 탭 키로 명령어 자동 완성을 지원합니다. 즉 tinker 에서 get_c 만 치고 탭 키를 치면 get_c 로 시작되는 메소드 목록을 모두 표시해 주며 get_cl 만 치고 탭을 치면 get_class 로 완성해 줍니다.

snake_case 메소드는 sn 으로 시작하는 메소드가 하나이므로 sn 만 치고 탭을 치면 자동으로 메소드 이름을 완성해 줍니다.


뷰에 전달된 데이타는 View 내부에 저장되며 with의 첫 번째 파라미터로 전달한 이름으로 접근할 수 있습니다.
>>> dd($v->tasks)  
array:2 [
  "name" => "Task 1"
  "due_date" => "2015-06-01"
]
=> null
PHP

라라벨 View 가 어떤 데이타 타입과 프로퍼티를 갖고 있는지 궁금한 독자들은 dump($v) 를 실행해 보면 궁금증이 좀 풀릴 것입니다.


REPL 이므로 화면에 출력하려고 하지만 바이너리 파일일 경우 tinker 의 포맷터가 출력하지 못 하므로 다음과 같은 예외가 발생하지만 정상 동작하므로 무시하면 됩니다.

InvalidArgumentException with message 'Incorrectly nested style tag found.'


위와 같이 tinker 는 애플리케이션을 디버깅할 경우 테스트 코드를 만들지 않고 빠르고 손쉽게 디버깅할 수 있으므로 익혀두면 유용하게 사용할 수 있으며 이 책에서도 여러 곳에서 tinker 를 사용하고 있습니다.