Notice
Recent Posts
Recent Comments
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

DeFacto-Standard IT

PHPStorm + Codeigniter 코드 자동완성(Code Completion) 활성화하기 본문

DEV tools/PHPStorm

PHPStorm + Codeigniter 코드 자동완성(Code Completion) 활성화하기

defacto standard 2018. 10. 27. 04:49

PHPStorm과 Codeigniter를 쓰면서 가장 불편했던 것은,

자바와 다르게 컴파일 언어가 아니라 스크립트 언어와 이에 대한 프레임워크라 그런지 코드 자동완성 기능이 아주 아주 부족하다는 것이다.


단, @property라는 PHP DOC 주석을 통해 IDE에 힌트를 제공하여 자동완성 기능을 사용할 수 있다.


이를 아는 개발자들은 보통 다음과 같이 Loader클래스를 사용하여 라이브러리나 모델 클래스의 인스턴스를 만들어 로드하고,

로드된 객체를 통해 함수 등을 수행한다.


class user_model {
public function echoModel() {
echo 'echo';
}
}


/**
* @property user_model $user_model
*/
class Welcome extends CI_Controller {
public function index() {
$this->load->model('user_model');
}

public function echoMethod() {
$this->user_model->echoModel();
}
}


위와 같이 PHP DOC 주석에 @property를 사용하는 방법을 통해,

user_model이라는 클래스가 존재한다는 것을 IDE에 힌팅으로 제공한다면 다음과 같이 코드 자동완성 기능이 동작하게 된다.



위는 Welcome 컨트롤러에 PHP DOC을 통해 user_model 클래스가 존재한다는 힌트를 제공해서 Code Completion을 수행시킨 결과다.


위와 같은 방법의 단점은,

Welcome 컨트롤러가 아닌 다른 컨트롤러에서 user_model을 사용할 때, 또 다시 다른 컨트롤러에 PHP DOC을 작성해야 한다는 점이다.


만약 user_model을 사용하는 모든 컨트롤러에 위와 같이 한다고 해도,

user_model의 이름이 변경된다면 모든 PHP DOC을 일일이 찾아서 변경해줘야 한다.


아무리 IDE에서 검색기능을 제공해서 이를 통해 수정한다고 하더라도, 노가다를 해야 하는 것은 변함 없으며,

여러 프로젝트가 존재한다면 user_model이 어느 프로젝트의 user_model인지 확인해야 한다는 점은 동일하다.



user_model을 사용하는 A라는 컨트롤러가 Welcome 컨트롤러를 상속한다면

A컨트롤러의 PHP DOC에는 user_model 에 대한 @property PHP DOC을 기술하지 않아도 상위 클래스의 PHP DOC에 의해 서브 클래스에서도 인식이 된다.


따라서 이를 응용한다면 편하게 자동완성 기능을 이용할 수 있을 것 같다.



CodeIgniter에서 컨트롤러를 정의하는 방법은, controller 폴더 내에 클래스를 정의하고 CI_Controller를 상속받는 것이다.


따라서 CI_Controller에서 user_model에 대한 @property PHP DOC을 기술한다면 모든 컨트롤러가 user_model을 인식하고 자동완성 기능을 사용할 수 있게 된다.


하지만 이 방법은 좋지 않다.


CI_Controller는 코드이그나이터의 Core단에 존재하는 클래스다.


코드이그나이터의 버전을 업그레이드할 때, 코어단의 소스가 변경되므로 user_model에 대한 @property PHP DOC은 사라지게 된다.


만약 코어단의 CI_Controller의 PHP DOC에 정의해놓은 @property가 많은 상태라면 처음부터 다시 모두 등록해야 한다.


기본적으로 프레임워크 코어단의 소스를 고치는 것은 아주 부적절하다.




하지만 일괄적으로 PHP DOC을 적용하는게 불가능한 것은 아니다.


다른 경로에 사용자가 만든 커스텀 CI_Controller를 인식시키게 하고,

이 커스텀 CI_Controller의 PHP DOC에 인식시키고 싶은 클래스들을 @property PHP DOC으로 지정하면 된다.


커스텀 CI_Controller를 만들면 기존의 CI_Controller를 동시에 인식하게 된다. 

이 상태에서 CI_Controller를 상속받으면, 같은 이름의 클래스가 2개라 IDE에서 노란 줄로 warning을 표시한다.

따라서 Core단에 존재하는 CI_Controller를 인식하지 않게 하는 작업도 필요하다.


이렇게 한다면 실제로는 코어단의 CI_Controller를 사용하므로 문제없이 동작하게 되고,

IDE에서 코딩할 때는 커스텀 CI_Controller를 인식하여 사용자가 정의한 라이브러리나 모델 클래스에 존재하는 메서드나 프로퍼티를 쉽게 자동완성으로 warning없이 깔끔하게 보여줄 수 있게 된다.


커스텀 CI_Controller는 코어단의 경로에 위치하지 않기 때문에,

코드이그나이터의 버전을 변경하더라도 개발자가 만든 소스로 인식되 덮어씌워지지도 않는다.




1. 다음 링크에서 phpstorm.php를 다운로드

https://github.com/natanfelles/codeigniter-phpstorm


2. phpstorm.php파일을 CI 프로젝트 최상단에 위치시킴



3. phpstorm.php의 CI_Controller, CI_Model 클래스에 @property를 활용하여 힌팅을 제공할 클래스 정보 입력

 * @property CI_Utf8             $utf8                                Provides support for UTF-8 environments
* @property Ispconfig $ispconfig This class enables you to use the ISPConfig 3 Remote API
* @property Boleto $boleto Boleto Class
* --------------------------------------------------------------------------------
* @property user_model $user_model
*/
class CI_Controller {

public function __construct()
{
}
}
 * @property CI_Xmlrpcs          $xmlrpcs                             XML-RPC server class
* @property CI_Zip $zip Zip Compression Class
* @property CI_Utf8 $utf8 Provides support for UTF-8 environments
* --------------------------------------------------------------------------------
* @property user_model $user_model
*/
class CI_Model {

public function __construct()
{
}
}


CI_Controller와 CI_Model의 @property PHP DOC에 user_model 등록한다면,

CI_Controller 및 CI_Model을 상속받는 클래스에서 user_model에 대한 클래스가 인식된다.



3. 프로젝트/system/core 로 이동해서, Controller.php와 Model.php를 선택 후 우클릭, 'Mark as Plain Text' 선택



코어단의 CI_Controller와 phpstorm.php의 CI_Controller를 동시에 인식하고 있어, IDE 상에서는 중복된 클래스 네임으로 warning 언더라인을 그린다.


따라서 Core단의 CI_Controller 인식을 못하게 하는 작업이다. IDE에서 Plain Text로 인식시킬 뿐, 소스코드에는 변경이 없으므로 배포하거나 실행해도 문제없이 동작한다.



4. 테스트


이제 CI_Controller 및 CI_Model을 상속받는 모든 클래스에서 주석 없이도 코드 자동완성이 동작하게 됐다.




한 가지 더 생각해볼 것이 있다.

라이브러리의 경우는 CI_Model이나 CI_Controller를 상속받지 않는다.


따라서 커스텀으로 작성한 CI_Model과 CI_Controller의 PHP DOC에 대한 영향을 받지 않는다.


어떤 경우에는 라이브러리에서 Model 등을 사용하게 될 수도 있다.


Loader 클래스를 사용하려면 $this 객체를 사용하여야 한다. 그래야만 $this->load->model('user_model')을 호출해서 사용할 수 있다.


문제는 이는 CI_Model 또는 CI_Controller를 상속받아야 하는 것인데, 이 중 어떤 것도 상속받지 않는 라이브러리의 경우는 Model의 사용 방법이 다르다는 것이다.



보통 라이브러리에서는 CI 객체를 &get_instance() 를 사용해 할당받아서 사용한다. 


get_instance()의 구현을 보면 CI_Controller::getInstance() 의 호출결과를 리턴한다.


이는 싱글톤으로 구현되어 있음을 의미하고, CI_Controller 클래스의 객체 자체가 리턴된다고 볼 수 있다.


따라서 CI_Controller에 @property PHP DOC을 등록해놓는다면,

이 정보들이 &get_instance()로 부터 리턴받은 객체에도 동일하게 적용되기 때문에 자동완성 기능을 쓸 수 있다.





물론 이러한 방법을 사용 할 때 주의할 점이 있다.


자동완성 기능은 위에서 말했듯이 @property PHP DOC에 기술된다면 해당 정보를 통해 출력된다.


이는 실제로 Loader 클래스를 사용해서 클래스의 인스턴스를 로드하지 않아도, 자동완성 기능 상으로는 사용할 수 있다는 얘기다.


Loader 클래스를 사용해서 로드하지 않고 그대로 사용한다면 당연히 에러가 날 것이다.


따라서 개발자들이 이를 간과하고 그대로 코드를 작성할 위험이 있다.


하지만 이는 PHP DOC을 사용해야 자동완성이 작동되는 것 자체의 문제이고,

phpstorm.php과 같은 커스텀 파일에 CI_Controller를 따로 정의해서 생기는 문제는 아니다.



require_once를 사용하지 않고, Loader 클래스를 통해 인스턴스를 로드하여 이를 사용한다는 코드이그나이터의 철학을 그대로 사용한다면 자동완성 기능을 PHP DOC을 등록해야만 사용할 수 있다는 것은 엄청난 단점으로 작용한다.


이를 보완할 수 있는 방법이므로, 차라리 특정 클래스를 사용하기 전에 확실히 로드했는지 잘 확인하고, 테스트를 충분히 하여 편한 개발을 할 수 있게 하는 것이 더 중요하다고 생각한다.

Comments