XE에서 모든 애드온은 같은 스코프에서 실행됩니다. 다른 애드온에서 선언한 변수를 마구 참조할 수 있지요. 그래서 내가 선언하지 않은 변수를 끌어다 쓰더라도 희한하게 작동하곤 합니다. 그러다가 다른 애드온이 없는 사이트에 가면 갑자기 작동을 안 해요.

 

반대로, 내가 쓰던 변수를 남겨놓으면 다른 애드온의 실행에 영향을 주거나, 심지어 코어에 오류를 일으킬 수도 있습니다. before_display_content 시점에서 $output 변수를 조작하는 경우가 대표적입니다. 여기서 $output 변수에는 화면에 뿌려줄 내용이 담겨 있는데, XE에서 쿼리 결과를 담는 변수명으로 흔히 $output을 쓰다 보니 애드온에서 무심코 쿼리를 쓰다가는 화면에 뿌려줄 내용을 날려먹기 일쑤입니다. (악명높은 백지화면의 가장 큰 원인 중 하나입니다.)

 

이런 오류를 피하려면 아래의 두 가지 규칙을 지켜야 합니다.

 

1. 내가 선언한 변수 외에는 사용하지 않는다.

2. 내가 선언한 변수는 내가 치운다.

 

그런데 이게 말처럼 쉽지가 않습니다. 특히 코드가 길어지면 어느 변수를 어디서 선언했는지 기억도 안 나요. 사용 후에 일일이 unset해주기도 귀찮습니다.

 

내가 쓰는 변수와 남이 쓰는 변수를 구분하는 가장 쉬운 방법은 함수 안으로 들어가는 것입니다. 함수 안에서는 함수 밖에 있는 변수를 건드릴 수 없고, 함수 안에서 선언한 변수는 함수 실행이 끝나면 자동으로 지워지니까요.

 

    function my_addon_function($addon_info, $called_position, &$output) {

        // 내 맘대로 변수 선언

    }

    my_addon_function($addon_info, $called_position, $output);

 

이렇게 하면 $addon_info, $called_position, $output 등 애드온에서 흔히 참조해야 하는 세 변수 외에는 모두 내맘대로 쓸 수 있게 됩니다.

 

그러나 PHP에서는 같은 이름의 함수를 여러 번 선언할 수 없기 때문에, XE 실행 과정에서 4번 실행되어야 하는 애드온에서 이렇게 하기에는 무리가 있습니다. 함수를 사용하는 애드온들이 func.php 등의 이름으로 함수 파일을 분리해 놓고 include_once로 처리하는 것은 이 때문이지요.

 

PHP 5.3부터는 익명 함수를 지원하므로 파일을 분리하지 않고도 깔끔하게 처리가 가능합니다. XE 최신 버전을 타겟으로 하는 애드온이라면 모두 이 문법을 사용할 수 있습니다.

 

    // 모든 애드온에서 사용 가능

    call_user_func(function() use($addon_info, $called_position, &$output) {

        // 내 맘대로 변수 선언

    });

 

이렇게 하면 여러 번 실행해도 상관없고, use() 문법을 사용해서 내가 사용할 변수만 싹 가져갈 수 있습니다. 함수나 클래스를 따로 선언할 필요가 없는 간단한 애드온이라면 이렇게 해 놓고 그 안에 내용을 작성하는 것이 안전합니다.

 

PHP 7.0부터는 심지어 아래와 같이 자바스크립트스러운 문법도 지원됩니다. 함수를 선언하자마자 곧바로 한 번 실행한 후 깔끔하게 폐기하는 거예요. 이건 뭐... $ 문자만 아니라면 PHP인지 자바스크립트인지 알 수도 없겠네요 ㅋㅋ (참고로 자바스크립트도 전역변수 때문에 오류가 많이 발생하기 때문에, 이렇게 함수를 선언해서 쓰는 것을 권장하는 추세입니다. IIFE라고 부릅니다.)

 

    // PHP 7.0 전용 애드온에서 사용 가능

    (function() use($addon_info, $called_position, &$output) {

        // 내 맘대로 변수 선언

    })();

 

단, 위에서 소개한 어느 방식을 사용하더라도 함수 안에서는 $this를 사용할 수 없다는 제약이 있습니다. before_module_proc, after_module_proc 등의 시점에서 $this를 조작해야 하는 애드온이라면 먼저 $this를 다른 변수에 할당한 후 넘겨야 하는데, 이런 목적으로는 관례상 $that을 사용합니다.

예:

 

    $that = $this;  // 오브젝트이므로 레퍼런스(&)를 사용할 필요 없음

    call_user_func(function() use($addon_info, $called_position, $that) {

        // 내 맘대로 변수 선언

        // $that->stop('에러메시지');

    });

 

기진곰

profile
GitHub @kijin 사람을 위한 인터넷 생태계의 발전에 많은 관심을 갖고 있습니다.
우리가 만들어 가는 XE의 새 이름, 라이믹스(Rhymix) 프로젝트에 참여하고 있습니다.
오픈소스 도로명주소 검색서버 및 API Postcodify를 개발, 운영중입니다.
국내외 서버 및 클라우드서버 세팅, 이전, 튜닝해 드립니다.
  • ?
    팁 감사합니다. 다른팁도 부탁드려요 ~~~ ㅎㅎ
  • ?
    팁 감사합니다~!
  • profile
    내변수를 안겹치게 길고복잡하게 만드는것도 좋겠네요ㅎㅎ