- 메타프로그래밍 할 때 필요한 그거. - 자세한 설명은 검색을.. 어디에 활용하면 좋을지는 함께 고민해보아요.
- 자바에 있는 그거.
Q. PHP가 그걸 지원해요?
A. 언어자체에서는 지원하지 않지만 뭐,, 어떻게든 그게 됩니다.
https://packagist.org/packages/doctrine/annotations
설치하기
composer require doctrine/annotations
오토로드에 등록해야합니다.
use Doctrine\Common\Annotations\AnnotationRegistry;
$autoload = require __DIR__ . '/vendor/autoload.php';
AnnotationRegistry::registerLoader([$autoload, 'loadClass']);
그리고 어노테이션을 추가합니다. Target 은 총 3가지입니다.
CLASS
PROPERTY
METHOD
각각 다음과 같이 정의할 수 있습니다.
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @Target({"CLASS"})
*/
class ClassAnnotated
{
/**
* @Required
*/
public $name;
}
/**
* @Annotation
* @Target({"PROPERTY"})
*/
class PropertyAnnotated
{
/**
* @Required
*/
public $name;
}
/**
* @Annotation
* @Target({"METHOD"})
*/
class MethodAnnotated
{
/**
* @Required
*/
public $name;
}
어노테이션을 사용하는 클래스.
/**
* @ClassAnnotated("this is user class maybe")
*/
class User
{
/**
* @PropertyAnnotated("this is username property maybe")
*/
protected $username;
/**
* @MethodAnnotated("this is constructor maybe")
*/
public function __construct($username)
{
$this->username = $username;
}
}
Annotation 불러오는 로직.
use Doctrine\Common\Annotations\AnnotationReader;
$reader = new AnnotationReader();
$classRefl = new ReflectionClass(User::class);
$propertyRefl = $classRefl->getProperty("username");
$methodRefl = $classRefl->getMethod("__construct");
print_r($reader->getClassAnnotations($classRefl));
print_r($reader->getPropertyAnnotations($propertyRefl));
print_r($reader->getMethodAnnotations($methodRefl));
(소스실습)
- 개발자가 가져야할 최고의 덕목은 게으름!!
- 일일이 외우지 말고 IDE를 활용합시다.
- 하지만, PHPStorm에서만.. 되요.
(자동완성실습)
일반적인 프로그램밍 언어는 다음 과정을 거치게 됩니다.
- 토큰분석
- 문법분석
- AST 생성 -> PHP로 이야기하면 이부분이 Opcache로. (아마도)
PHP를 생각해봅시다.
파일 바꾸고 첫번째 리퀘스트는 오래걸리지만 그 다음 부터는 캐시때문에 빠르게 처리합니다. 즉, 문법 분석 비용이 가장 큽니다. 캐시만 사용해도 성능을 충분히 끌어올릴 수 있습니다.
추가 패키지를 설치합니다.
composer require doctrine/cache
기존 소스를 다음으로 교체.
doctrine에는 엄청나게 많은 캐시를 제공해줍니다.
- http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/caching.html
- https://github.com/doctrine/cache/tree/master/lib/Doctrine/Common/Cache
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\CachedReader;
$reader = new CachedReader(new AnnotationReader(), new Doctrine\Common\Cache\FilesystemCache(__DIR__));
- PHP에서 클래스를 생성할 때, PHP 내부에서는 zend_class_entry라는 구조체가 선언이 됩니다.
- Reflection 객체 생성 = 이미 생성되어있는 zend_class_entry 구조체 연결 객체 생성
- 즉, 일반 객체 생성비용과 거의 비슷합니다.
어려우니까 그냥 진짜 그런지 확인하고 갑시다.
class Dummy {}
class HelloWorld
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
$benchmark->add("reflection", function () {
$reflection = new ReflectionClass(Dummy::class);
$reflection->getName();
});
$benchmark->add("basic", function () {
$reflection = new HelloWorld(Dummy::class);
$reflection->getName();
});
$benchmark->run();
결과는..?
- Annotation 재밌으니 사용해봅시다.
- symfony 강추추, doctrine 강추추.
- Reflection 안느려요.
- https://symfony.com/doc/3.2/routing.html
- http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html
PHP RFC에 거의 매년 Annotation 관련 논의가 올라옵니다. 물론 이것도 반영 안되겠지만.. PHP8정도 되면 혹시 적용되지 않을까요? :-)