본문 바로가기
개발/PHP

PHP Autoload와 namespace

by 똘똘이박사 2018. 6. 21.

PHP Autoload와 Namespace



지난 포스팅에서 PHP autoload 에 대해서 알아 보았습니다.

이번 포스팅에서는 autoload 를 좀더 깊이 있게 다룰 수 있는 방법에 대해 이야기 해보려고 합니다.


autoload를 좀더 잘 활용 하려면 namespace 라는 것을 알고 있어야 합니다.

JAVA에 비유하자면 package 와 유사 합니다.


namespace 는 동일한 이름을 가진 class 가 존재할 때 구분하여 쓸 수 있는 용도로 사용됩니다.


예를 들어 

게시판에서 사용하는 목록 조회 클래스명이 List 라고 가정을 해봅니다.

그런데 방명록의 목록을 조회 하는 클래스명이 관리 하기 편하게 하기 위해 List 로 만들었습니다.

그리고 이 것을 한 화면에 보여 주기 위해 두 클래스를 모두 호출 합니다.


그런데 여기서 부터 문제가 생깁니다.

어떤 List 클래스가 게시판 목록인지, 방명록 목록인지 알 수가 없습니다.

이런 혼동을 방지하려고 게시판 목록은 BoardList라든지 방명록 목록은 GuestList 라든지 하는 방법으로

좀더 명확하게 나누어 만들어 줄 수 있겠지만

만약 본인이 만들지 않은 프로그램을 받아서 이용할 경우는 

어디서 똑같은 이름의 클래스가 어떤 용도로 사용되는지 알 방법이 없습니다.

이런 충돌위험을 미연에 방지하기 위해 namespace 를 사용합니다.


모던 PHP를 지향하는 PHP-PSR(PHP Standard Recommendation)에서는 autoload 를 위해

namespace 사용법을 조금더 구체적으로 명시하고 있습니다.


PSR에서 권장하는 namespace의 규약은 다음과 같습니다.


  • namespace 최상위namespace\subnamespace\하위namespace;

       - 최상위 namespace 는 회사명이나 개인인 경우 ID 등으로 한다.

       - subnamespace 는 패키지 명으로 한다.

       - 하위 namespace 는 클래스 명을 따른다.


  • namespace 는 물리적 디렉토리에 대응 하도록 만든다.


이전 포스팅에서 사용했던 autoload 를 조금 수정해서 namespace 를 만들어 보도록 하겠습니다.

우선 이전 소스에서 autoload 에 대한 내용은 잊고, 다시 require_once 로 클래스들을 불러 오도록 할 것인데

namespace 에 대응하는 물리적 디렉토리를 만들기 위해 아래와 같은 구조로 변경을 하겠습니다.


 

                    


vender/autoload.php 는 지금 당장 쓰지 않지만

이 포스팅의 마지막에는 쓰일 예정이므로 미리 vender 디렉토리를 만들고 autoload.php 파일을 옮겨 두었습니다.

그리고 Task01.php 파일을 복사하여 Task02.php 파일을 만들고 클래스 명을 Task02 라고 하였습니다.


위의 디렉토리 구조를 PSR nsmaspace 권장 사항을 적용하여 namespace 를 만든다면 아래와 같은 형식으로 만들 수 있습니다.


 namespace chobo\hello;

 namespace cohbo\tasks;


권장사항에서와의 차이 점이라면 하위 namespace에 클래스 명을 적어 준다고 하였지만

실제적으로 디렉토리 구조에 대응하도록 작성 하도록 합니다.


위의 구조와 동일하게 디렉토리를 생성하고 파일들을 옮겼다면 이제 namespace를 각 파일의 상단에 적어 줍니다.


namespace 사용 규칙2

  • namespace 는 각 문서의 최상단에 위치 한다.
  • namespace 간의 구분은 역슬레쉬('\')로 한다.


이 규칙을 적용하여 수정한 문서들의 내용은 아래와 같습니다.


chobo/hello/Hello.php


<?php

namespace chobo\hello;


class Hello

{

    public function say()

    {

        echo "Hello- PHP!";

    }

}



chobo/tasks/Task01.php


<?php

namespace chobo\tasks;


class Task01

{

    public function todoTask()

    {

        echo "todo Task01";

    }

}


chobo/tasks/Task02.php


<?php

namespace chobo\tasks;


class Task02

{

    public function todoTask()

    {

        echo "todo Task02";

    }

}



이제 index.php 를 수정해 봅니다.


index.php 


<?php

//require_once 'vender/autoload.php';

require_once 'chobo/hello/Hello.php';

require_once 'chobo/tasks/Task01.php';

require_once 'chobo/tasks/Task02.php';


$sayHello = new \chobo\hello\Hello();

$sayHello->say();


echo '<br>';


$task01 = new \chobo\tasks\Task01();

$task01->todoTask();


echo '<br>';


$task02 = new \chobo\tasks\Task02();

$task02->todoTask();



붉은색 글자로 표시한 부분은 모두 새로 추가된 문장이고

음영 처리한 부분은 주석 처리를 위해 수정한 부분입니다.


이제 index.php 를 실행해 봅니다.

오타만 없다면 위와 같은 화면이 나올 것입니다.


이제 namespace 를 작성하는 것이 물리적 디렉토리와 어떻게 연관이 되는지 알 수 있습니다.


그럼 이제 autoload를 적용해 require_once를 몽땅 정리해 보도록 하겠습니다.


index.php 수정


<?php

require_once 'vender/autoload.php';


$sayHello = new \chobo\hello\Hello();

$sayHello->say();


echo '<br>';


$task01 = new \chobo\tasks\Task01();

$task01->todoTask();


echo '<br>';


$task02 = new \chobo\tasks\Task02();

$task02->todoTask();



require_once가 모두 사라져 코드 간결해 졌습니다.


다시 index.php 를 실행해 봅니다.

오류가 발생합니다. 왜? 일까요?

autoload.php 를 아래와 같이 수정하여 어떻게 클래스를 불러 오는지 보도록 하겠습니다.


vender/autoload.php 수정


<?php

spl_autoload_register(function ($class){

    echo 'class path : '. $class;

    exit();

    //require_once $class.'.php';

});


이상한 부분을 발견 했나요?


경로 부분의 문자가 역슬러쉬('\') 로 되어 있습니다.

namespace에서 사용된 경로가 모두 $path로 넘어 오는 것을 알 수 있습니다.

리눅스 안에서 경로를 구분할때 사용하는 문자는 슬러쉬('/') 입니다.

따라서 역슬러쉬('\')를 모두 슬러쉬('/')로 바꿔 주어야 합니다.

PHP str_replace 문을 이용해 변경해 주는 구문을 추가 합니다.

아래위 구문을  아래 첫줄에 추가해 줍니다.


    $class = str_replace('\\', '/', $class);


vender/autoload.php 수정


<?php

spl_autoload_register(function ($class){

    $class = str_replace('\\', '/', $class);

    echo '<h3>class path : '. $class.'</h3>;

    //exit();

    require_once $class.'.php';

});




이제 다시 실행해 봅니다.


이제 제대로 출력이 됩니다.


여기서 의문이 생김니다.

객체를 생성할때 경로를 모두 적어 주었기 때문에 결과적으로 클래스 파일을 잘 읽어 올 수 있었던거 아닌가?


그럼 확인을 해봅시다.

정말 그런지

Hello.php 파일에서 상단위 namespace 문장을 주석처리 하고 실행해 봅니다.

에러가 발생합니다.

클래스를 찾을 수가 없다는 메시지가 출력됩니다.


이제 namespace와 autoload 를 어떻게 사용해야 할지 감이 잡혔으리라고 생각합니다.



제 글을 공유하시거나 인용하실때는 출처를 남겨주세요.

이 포스팅의 소스는 깃허브(https://github.com/freehoon/workspace/tree/master/phpAutoloadSample3)에 공개 되어 있습니다.


반응형