너의 개발은/PHP

PHP: MVC(Model, View, Controller)

MVC(Model, View, Controller)

모델, 뷰, 컨트롤러로 분리하는 이 아키텍쳐는 많은 프레임워크에서 사용되는 개념이다. 모델은 코드상 어플리케이션에서 사용되는 데이터인 데이터베이스를 클래스화 시켜놓은 것이라고 볼 수 있다. 는 말 그대로 보여주기만 한다. 마지막으로 컨트롤러는 모델과 소통하여 뷰에게 현재의 상태를 알려주게 되는 것이다.

 

물론 위의 설명이 정확한 것이라고 볼 수는 없겠지만, 대체로 모델은 '무엇' 을 어플리케이션에게 제공(대체로 데이터)할 것이며, 컨트롤러는 '어떻게' 처리할 것인지에 대한 것이라고 보면 좋겠다. 이를 코드로 한정지어 이해할 필요는 없다. 이를테면 위에서 모델은 '클래스화 시켜 놓은 것' 이라고 했지만, 그것은 단지 코드에서일 뿐이다.

모델

우리가 블로그를 만든다고 가정하고, 먼저 간단한 Post 모델을 만들어보자. 라라벨과 같은 프레임워크에서는 ORM(Object-relational mapping)을 사용하여 직접 데이터베이스에서 객체를 얻어오지만, 우린 그러지 않을 것이다. 간단하게 가자.

class Post
{
    public $title;
    public $content;
    public $id;

    public function __construct($id, $title, $content) 
    {
        $this->title = $title;
        $this->content = $content;
        $this->id = $id;
    }
}
DAO, DTO, VO 같은 개념을 그다지 좋아하지 않으므로 언급하지 않는다. 굳이 사용하고 싶지 않다.

자 그럼 이제 뷰를 다음과 같이 작성하자. 뷰는 그저 데이터를 보여주면 그만이다. 단순히 post 객체에 있는 본문을 출력 할 뿐이다. 이 녀석의 파일 이름은 HelloWorld.php 로 지었다. 굳이 언급하는 이유는 아래에서 쓸 것이기 때문이다.

echo $post->content;

view 라는 함수를 만들어보자. 이것은 컨트롤러에서 사용할 것이며 뷰를 반환할 때 사용할 것이다. 아래의 함수는 넘어온 스크립트를 포함(include)하고, 내부 스코프에서 변수를 선언해준다는 것 이외의 역할은 없다.

function view($view, $vars = []) 
{
    foreach ($vars as $name => $value) {
        $$name = $value;
    }
    
    include $view;
}

컨트롤러

컨트롤러를 사용할 때는 보통 라우터를 함께 사용한다. 따라서 우리는 라우터를 먼저 만들 것이다. 이것은 그다지 어렵지 않다. Route::add() 메서드는 라우트를 등록하고, Route::run() 메서드는 $_SERVER['REQUEST_METHOD']$_SERVER['PATH_INFO'] 와 같은 정보를 사용하여 현재 경로를 파악하고, 콜백함수를 실행시켜준다.

class Route
{
    private static $routes = [];

    public static function add($method, $path, $callback)
    {
        self::$routes[] = compact('method', 'path', 'callback');
    }

    public static function run()
    {
        return call_user_func(
            current(
              array_filter(self::$routes, fn ($route) => self::match($route['method'], $route['path']))
            )['callback']
        );
    }

    private static function match($method, $path)
    {
        return $method === strtolower($_SERVER['REQUEST_METHOD']) && ($path === ($_SERVER['PATH_INFO'] ?? '/'));
    }
}
메서드가 꼭 정적 메서드일 필요는 없다. 이는 그저 편의를 위해 만든 것이다.

자 그럼 이제, 컨트롤러를 하나 만들자. IndexController::index()Post 를 하나 만들고, view 를 반환하게 된다.

class IndexController
{
    public static function index()
    {
        $post = new Post(
            1, 
            'Lorem Ipsum', 
            'Lorem Ipsum is simply dummy text of the printing and typesetting industry.'
        );
        
        return view('HelloWorld.php', compact('post'));
    }
}
일반적으로 새로운 포스트를 만들고 등록하는 일은 PostController::create() 에서 하게 될 터이나, 편의상 여기서 만든다.

index.php

이제 직접 서버를 돌릴 Document Root 에선 어떻게 해주면 좋을까? 간단하다. Route::add() 로 라우트를 등록하고, 그것을 실행해버리면 된다. 아주 간단하지 않은가?

 

참고로 라우터를 사용하면 레거시를 사용하듯 다수의 php 파일에서 고통받을 필요가 없어진다. index.php 에서 모든 요청을 처리하고 라우터가 알아서 컨트롤러 로직으로 찾아갈 수 있도록만 해주면 된다.

Route::add('get', '/', 'IndexController::index');

Route::run();

 

 

PHP 7+ 프로그래밍: 리부트 - 인프런

기초 문법부터 내장 함수, 웹 보안, 게시판 만들기까지 PHP 언어를 시작하는 분들을 위해 바이블이 될 수 있게 만들어보고자 하는 마음으로 이번 강좌를 만들어보았습니다. 입문 웹 개발 프로그��

www.inflearn.com

 

PHP 7+ 프로그래밍: 객체지향 - 인프런

PHP 객체지향, 내장 클래스, PSR, Composer, MVC(Model, View, Controller)까지 모던 PHP를 익히기 위한 근간을 이야기합니다. 초급 프로그래밍 언어 알고리즘 PHP 객체지향 알고리즘 온라인 강의 모던 PHP 프로��

www.inflearn.com

'너의 개발은 > PHP' 카테고리의 다른 글

PHP: PSR(PHP Standard Recommendation)  (0) 2020.08.15
PHP: 의존성 관리자 — Composer  (0) 2020.08.14
PHP: MVC(Model, View, Controller)  (0) 2020.06.29
PHP: 파일 업로드와 다운로드  (0) 2020.06.10
PHP: 데이터베이스 (MySQLi, PDO)  (0) 2020.06.10
PHP: 쿠키와 세션  (0) 2020.04.29