Pull to refresh

PHP NameSpace — как же все-таки его готовить?

Reading time4 min
Views21K
PHP, начиная с версии 5.3, подарил нам пространство имен. С тех пор идет где-то вялое, а где-то бурное обсуждение, как же это пространство имен использовать?
Некоторые фреймворки, такие как Symphony, Laravel, и, конечно же Zend взяли эту технологию на вооружение.
Все это более или менее вписалось в схему MVC. Осталась одна, наверное вечная, дискуссия, какой же должна быть главная брачная пара приложения — Модель и Контроллер?
Одни нам говорят, что Модель должна быть дородной и толстой и при ней стройный и тонкий Контроллер. Одним словом — матриархат.
Другие, наоборот, считают, что Контроллер должен всем управлять и повелевать, поэтому он получается основательный, упитанный. И при нем худенькая, стройненькая Модель, задача которой сводится к подай-принеси. Такой вот патриархат.
Так что же лучше в схеме MVC? Патриархат или матриархат?
Давайте посмотрим на это с точки зрения построения семейной ячейки на основе демократии. И пусть Namespace нам в этом поможет.

Нам не нравятся толстые, неуклюжие Контроллеры, которые, как слон в посудной лавке, по неосторожности могут раздавить все приложение.
Нам не нравятся также толстые Модели. Ну а кому они нравятся? Они должны быть достойны подиума!
Давайте попробуем с помощью Namespace, как с хорошей сватьей, создать гармоничную семью.

Сначала создадим каркас приложения. Как это ни банально, но пусть это будет блог.

image

Мы создали основну структуру, где:
  • Blog — это хранилище нашего приложения;
  • Views и Templates — хранилище представлений и шаблонов;
  • Utility — хранилище общих библиотек;
  • index.php — bootstrap скрипт;
  • Post — вот здесь и должна состояться семейная идиллия Контроллера и Модели.

С index.php все просто:
<?php
use Blog\Blog as Blog;
/*
 *   main application
 */

define ("APP_PATH", "/home/oleg/www/viper.dev/");
define ("VIEW_PATH", "/home/oleg/www/viper.dev/Blog/Views/");

spl_autoload_register(function ($class) {
      require_once str_replace('\\', '/', $class). '.php'; 
      });

$blog = new Blog();

$blog->run();

/*
 * end of index.php
 */


Определяем нужные пути и создаем автозагрузчик.
Автозагрузчик загружает необходимые классы, которые расположены в иерархии папок согласно пространству имен класса. Например, класс Blog\Post\Services\View будет разыскиваться в Blog/Post/Services.
А вот и первая встреча с Namespace.
При старте index.php мы создаем экземпляр приложения Blog, класс которого загружается из Blog/Blog.php.
Посмотрим на него.

<?php namespace Blog;
use Blog\Post\Post as Post;

class Blog  
{
    public $post;

    public function __construct()
    {
        $this->post = new Post();
    }

    public function run() 
    {
        $this->post->view->all();
    }

}//end class Blog

При создании класса Blog мы внедряем в него класс Post с Namespace Blog\Post и автозагрузчик загружает его из Blog/Post/Post.php.
Наверное, этот класс и можно назвать Контроллером,
<?php namespace Blog\Post;
use Blog\Post\Services\View as View;

class Post  
{
     public $view;

     public function __construct() 
     {
         $this->view = new View();
      }
}//end class Post

Сущность Post включает в себя:
— структуру самой записи данных — Blog\Post\Entities\PostEntity.php
<?php namespace Blog\Post\Entities;

class PostEntity
{
     public $id;
     public $title;
     public $body;
}//end class

— службы, обслуживающие запросы Контроллера — Blog\Post\Services\View.php (одна из служб, для примера)
<?php namespace Blog\Post\Services;
use Blog\Utility\Contemplate as Contemplate;
use Blog\Post\Repositories\Db as DB;

class View  
{
   public $db;

  public function __construct()
  {
       $this->db = new DB();
  }//end __construct

  public function all()  
  {
        $posts = $this->db->survey();
	Contemplate::compose(array(
         'header' => 'header',
         'main' => 'main',
         'footer' => 'footer',
         ),
         array(
         'posts' => $posts,
         'title'  => 'Viper site',
         ));
  }
}//end class PostView

— систему взаимодействия с базой данных — Blog\Post\Repositories\DB.php — вот она, наша тонкая, изящная Модель,
Только подай-принеси, и ничего больше!
<?php namespace Blog\Post\Repositories;
use PDO as PDO;

class DB  
{
    private $dbh;

    public function __construct() 
    {
        $user = 'user';
        $pass = 'parole';
        try 
        {
             $this->dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
                PDO::ATTR_PERSISTENT => true ));
        } catch (PDOException $e) {
              echo "Error!: " . $e->getMessage() . "<br/>";
              die();
        }
    }//end __construct

  public function survey()
  {
    $query_view = $this->dbh->prepare('SELECT * from posts');
    $query_view->execute();
    return $query_view->fetchAll(PDO::FETCH_CLASS, "Blog\Post\Entities\PostEntity");
  }//end survey

}//end class Db

В результате нам удалось создать структуру приложения, где все компоненты хорошо связаны, при этом мы добились четкого разделения классов, где каждый класс выполняет свою задачу. Контроллер у нас тонкий и в то же время мощный. Модель под стать ему. Идеальная семья!
И все багодаря Namespace.

Не спорю, во многих случаях удобен фреймворк. Но, посмотрите, Namespace вам ничего не напоминает?
Четкое разделение на классы, строгая, и в тоже время гибкая, полностью подчиненная разработчику иерархия каталогов и классов.
Отсутствие порою такого весомого довеска в виде сотен файлов и классов в виде фреймворка.
Отсутствие прокрустова ложа правил взаимодействия классов и компонентов.

Статья навеяна размышлениями на эту тему Taylor Otwell, автора фреймворка Laravel, за что ему огромное спасибо.
Адрес исходников примера на GitHub: https://github.com/oleg578/PHPNamespaceModel
Tags:
Hubs:
Total votes 30: ↑7 and ↓23-16
Comments9

Articles