Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

PHP Namespace & use & MVC

Лекция



Привет, Вы узнаете о том , что такое php namespace, Разберем основные их виды и особенности использования. Еще будет много подробных примеров и описаний. Для того чтобы лучше понимать что такое php namespace, mvc , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend) .

Пространство имен (англ. namespace) — некоторое множество, под которым подразумевается модель, абстрактное хранилище или окружение, созданное для логической группировки уникальных идентификаторов (то есть имен). Идентификатор, определенный в пространстве имен, ассоциируется с этим пространством. Один и тот же идентификатор может быть независимо определен в нескольких пространствах. Таким образом, значение, связанное с идентификатором, определенным в одном пространстве имен, может иметь (или не иметь) такое же (а скорее, другое) значение, как и такой же идентификатор, определенный в другом пространстве. Языки с поддержкой пространств имен определяют правила, указывающие, к какому пространству имен принадлежит идентификатор (то есть его определение).wiki


Все ясно? На самом деле все просто. До версии 5.3 в php существовало всего два пространства — глобальное(в котором выполнялся ваш основной код) и локальное(в котором определялись переменные функций).
PHP Namespace & use & MVC
С версии 5.3 все изменилось. Теперь можно определить свое пространство имен, в котором будут существовать ваши классы методы и т.д.
PHP Namespace & use & MVC
Надеюсь стало немного понятнее.

Я специально обозвал классы одинаково. Так они определены в разных пространствах, то это два разных класса, несмотря на одинаковые имена. Основной скрипт,-по прежнему, функционирует в глобальном пространстве, здесь ничего не изменилось и в нем, по-прежнему, можно определять классы и функции. Так для чего же тогда нужны пространства? Прежде всего, для уверенности в том, что когда вы подключаете файл, с каким-нибудь фреймворком или библиотекой, ваши классы не переопределят классы фреймворка или наоборот.

Для того, чтобы использовать классы определенные в своем пространстве имен, необходимо в нужном месте(я как правило предпочитаю делать это в начале файла) импортировать определенное вами пространство в глобальное для этого используется ключевое слово
use

Внимание: по каким-то своим основаниям php не допускает использование ключевого слова use в блоках условий и циклах


возьмем пример с картинок и воплотим его в коде:
Внимание: ключевое слово namespase должно быть расположено в самом начале файла сразу после <? php

файл A.php

<? php
namespace A
{ 
  class A
  {
    public static function say()
    {
      echo 'Я пространство имен А';
    }
  }
}

файл B.php

<? php
namespace B
{ 
  class A
  {
    public static function say()
    {
      echo 'Я пространство имен B';
    }
  }
}

Возможен альтернативный синтаксис:

<? php
namespace A;
  class A
  {
    public static function say()
    {
      echo 'Я пространство имен А';
    }
  }


Рекомендуется объявлять каждое пространство имен в отдельном файле. Хотя можно и в одном, но это строго не рекомендуется!
Теперь переместимся в третий файл, в котором будет функционировать наш основной скрипт
index.php

<? php
require_once 'A.php';
require_once 'B.php';

use A\A;
use B\A;

казалось бы в чем преимущество, только кода прибавилось, однако это не совсем так, чуть дальше я приведу пример класса автозагрузки, с которым строки подключающие файлы с классами будут ненужны.
А теперь обратимся к нашим классам

<? php
require_once 'A.php';
require_once 'B.php';

use A\A;
use B\A;

A\A::say();
B\A::say();

Внимание: использование оператора разрешения области видимости (::) в пространствах имен php не допускается! Единственное для чего он годится — это для обращения к статичным методам класса и константам. Вначале хотели использовать для пространства имен именно его, но затем из-за возникших проблем отказались. Поэтому конструкция вида A::A::say(); недопустима и приведет к ошибке.

Для пространств имен необходимо использовать символ обратного слеша "\"
Внимание: во избежание недоразумений необходимо экранировать данный символ при его использовании в строках: '\\'


Пространства имен можно вкладывать друг в друга, дополним наш файл A.php:

<? php
namespace A
{ 
  class A
  {
    public static function say()
    {
      echo 'Я пространство имен А';
    }
  }
  
}

namespace A\subA
{ 
  class A
  {
    public static function say()
    {
      echo 'Я подпространство имен А';
    }
  }
}

а в индексе напишем следующее:

<? php
require_once 'A.php';
require_once 'B.php';

use A\A as A;
use B\A as B;
use A\subA as sub

A::say();
A::say();
sub::say();


Важным моментом является использование алиасов для импортированных пространств. Об этом говорит сайт https://intellect.icu . Можно было написать A\subA::say(); согласитесь, каждый раз писать полные пути к пространствам затруднительно для того, чтобы этого избежать были введены алиасы. При компилировании произойдет следующее вместо алиаса sub будет подставлено A\subA, таким образом мы получим вызов A\subA::say();

А что же тогда происходит при вызове функций определенных в глобальном пространстве? PHP сначала ищет функцию внутри того пространства, где вы сейчас работаете, и в случае если не находит, то обращается к глобальной области видимости. Для того, чтобы сразу указать, что вы используете глобальную функцию необходимо перед ней поставить обратный слеш. 

Для того чтобы не было проблем с автозагрузкой классов из пространств файловую систему нужно организовать аналогично организации пространств. Например, есть у нас корневая папка classes, где и будут храниться наши классы, тогда наши пространства могут быть организованы следующим образом
classes\A\A.php
classes\A\sub\A.php(подпространство sub вынесем в отдельный файл)
classes\B\B.php

В php есть магическая константа __NAMESPACE__ которая содержит имя текущего пространства.

А теперь об автозагрузке.


Приведенный ниже класс не мой, я только сделал его рабочим и немного усовершенствовал взят отсюдова.
Внимание:Для того, чтобы ваши классы загружались имя класса должно совпадать с именем файла!



<?php
namespace yourNameSpace
{ 
  class Autoloader
  {
    const debug = 1;
    public function __construct(){}

    public static function autoload($file)
    {
      $file = str_replace('\\', '/', $file);
      $path = $_SERVER['DOCUMENT_ROOT'] . '/classes';
      $filepath = $_SERVER['DOCUMENT_ROOT'] . '/classes/' . $file . '.php';

      if (file_exists($filepath))
      {
        if(Autoloader::debug) Autoloader::StPutFile(('подключили ' .$filepath));
        require_once($filepath);
        
      }
      else
      { 
        $flag = true;
        if(Autoloader::debug) Autoloader::StPutFile(('начинаем рекурсивный поиск'));
        Autoloader::recursive_autoload($file, $path, &$flag);
      }
    }

    public static function recursive_autoload($file, $path, $flag)
    {
      if (FALSE !== ($handle = opendir($path)) && $flag)
      {
        while (FAlSE !== ($dir = readdir($handle)) && $flag)
        {
          
          if (strpos($dir, '.') === FALSE)
          {
            $path2 = $path .'/' . $dir;
            $filepath = $path2 . '/' . $file . '.php';
            if(Autoloader::debug) Autoloader::StPutFile(('ищем файл <b>' .$file .'</b> in ' .$filepath));
            if (file_exists($filepath))
            {
              if(Autoloader::debug) Autoloader::StPutFile(('подключили ' .$filepath ));
              $flag = FALSE;
              require_once($filepath);
              break;
            }
            Autoloader::recursive_autoload($file, $path2, &$flag); 
          }
        }
        closedir($handle);
      }
    }
  
    private static function StPutFile($data)
    {
      $dir = $_SERVER['DOCUMENT_ROOT'] .'/Log/Log.html';
      $file = fopen($dir, 'a');
      flock($file, LOCK_EX);
      fwrite($file, ('║' .$data .'=>' .date('d.m.Y H:i:s') .'<br/>║<br/>' .PHP_EOL));
      flock($file, LOCK_UN);
      fclose ($file);
    }
    
  }
  \spl_autoload_register('yourNameSpace\Autoloader::autoload');
}

Если посмотреть на имена классов, которые приходят для загрузки, то будет видно, что каждый класс предваряется префиксом из пространства имен, которое указано в use. Именно поэтому рекомендую использовать расположение файлов в каталогах аналогично пространству имен, это ускоряет поиск до одной-двух итераций.

Теперь наш индекс можно написать так:

<? php
require_once 'Autoloader.php';
use Autoloader as Autoloader;
use A\A as A;
use B\A as B;
use A\subA as sub

A::say();
A::say();
sub::say();

теперь все классы и интерфейсы, которые вы будет использовать будут загружены автоматически.

Для демонстрации некоторых динамических возможностей языка с пространствами объявим еще один класс:
test.php

<? php
namespace mySpace
{
  class test
  {
    __construct()
    {
      //конструктор;
    }

    function sayName($name)
    {
      echo 'Привет ' . $name;
    }
    static function sayOther()
    {
      echo 'статичный вызов';
    }
  }
}


index.php

<? php
require_once 'Autoloader.php';
use Autoloader as Autoloader;

use mySpace\test as test
//можно, например сделать так
$class = 'test';
//приведет к вызову конструктора
$obj = new $class;
$obj->sayName('test');
//а можно так
test\sayName('test2');
//или так
$obj::sayName('test');
//а можно так
test::sayName('test2');


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

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

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

PHP Namespace & use & MVC


Мы создали основну структуру, где:
  • 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, за что ему огромное спасибо.

В заключение, эта статья об php namespace подчеркивает важность того что вы тут, расширяете ваше сознание, знания, навыки и умения. Надеюсь, что теперь ты понял что такое php namespace, mvc и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)

создано: 2016-03-08
обновлено: 2021-03-13
132631



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)

Термины: Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)