Автозагрузка в PHP: начали за здравие, а кончили за упокой

Original author: Francois Zaninotto
  • Translation

Предисловие переводчика


Данная статья является вольным переводом-пересказом поста The End of Autoloading
. Оригинальная статья не первой свежести, поэтому код приведенный в примерах может быть не актуален. В теме, которую затрагивает статья, самое главное — общий взгляд, а не конкретные примеры.

Предисловие


Автозагрузка в PHP отлично экономит время. Это позволяет писать скрипты не задумываясь о путях к библиотекам, которые вы используете. Но с приходом неймспейсов и под влиянием Java-стиля современных фреймворков ситуация изменилась. В ближайшем будущем автозагрузка будет повсеместно, но без единой выгоды старого ее стиля.


До автозагрузки. Пути к файлам.


До появления автозагрузки, в каждом скрипте необходимо было указывать пути к используемым библиотекам. Исходный код выглядел так:

<?php
require_once 'PEAR.php';
require_once 'PEAR/DependencyDB.php';

class PEAR_Registry extends PEAR {
  //...
}

Зависимости явно прописывались в начале каждого скрипта. В этом примере зависимость очевидна, даже если вызов PEAR_DependencyDB находится на 328 строке.

Приход SPL-автозагрузки.


Позже появилась функция spl_autoload_register(), позволившая убрать вызовы require/require_once. Замечательным было то, что теперь появилась возможность использовать классы без необходимости знания где они расположены. Например:

<?php
class postActions extends sfActions
{
  public function executeList()
  {
    $this->posts = PostPeer::doSelect(new Criteria());
  }
}

Смотрите, здесь нет ни единого вызова require/require_once, при том, что этот класс зависим от sfActions, PostPeer, и Criteria классов. Разработчики смогли заниматься бизнес-логикой, не тратя время на поиск путей зависимостей. Это было действительно удобно.

Реализации автозагрузки.


Реализации автозагрузки варьируются. Некоторые библиотеки используют список всех классов, которые нужно подключить. Например:

<?php
class Propel
{
  // ..
  protected static $autoloadMap = array(
    'DBAdapter'      => 'adapter/DBAdapter.php',
    'DBMSSQL'        => 'adapter/DBMSSQL.php',
    'MssqlPropelPDO' => 'adapter/MSSQL/MssqlPropelPDO.php',
    'MssqlDebugPDO'  => 'adapter/MSSQL/MssqlDebugPDO.php',
    // etc.
}

Эта техника позволила скрыть пути к классам, но заставила разработчика библиотеки обновлять “карту” автозагрузки, каждый раз, при добавлении нового класса. Другая техника использует проход по структуре папок проекта в поиске нужного класса. Такой подход позволил подменять классы фреймворка своими, т.к. проход по папкам происходил в определенном порядке: пользовательские папки, проекта, плагинов и фреймворка. Таким образом разработчик мог создать класс ClassName, который подменит ClassName предоставленный плагином, т.к. загрузится раньше.

Автозагрузка с неймспейсами


Приход неймспейсов изменил техники автозагрузки. Авторы фреймвроков объединились, что бы унифицировать техники автозагрузки, для возможности технического взаимодействия между различными библиотеками. Было решено, что явное лучше неявного и полное имя класса будет относительным путем к файлу.

\Doctrine\Common\IsolatedClassLoader
  => /path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php
\Symfony\Core\Request
  => /path/to/project/lib/vendor/Symfony/Core/Request.php
\Zend\Acl
  => /path/to/project/lib/vendor/Zend/Acl.php
\Zend\Mail\Message
  => /path/to/project/lib/vendor/Zend/Mail/Message.php

Были выработаны принципы именования и файловой структуры, а также реализация класса SplClassLoader. Этот подход сейчас используется практически во всех современных фреймворках. Пример кода:

<?php
namespace Application\HelloBundle\Controller;
use Symfony\Framework\WebBundle\Controller;

class HelloController extends Controller
{
  public function indexAction($name)
  {
    $author = new \Application\HelloBundle\Model\Author();
    $author->setFirstName($name);
    $author->save();
    return $this->render('HelloBundle:Hello:index', array('name' => $name, 'author' => $author));
  }
}

Здесь все также нет require благодаря автозагрузке. Автозагрузчик ищет Symfony\Framework\WebBundle\Controller класс в файле Symfony/Framework/WebBundle/Controller.php.
Все хорошо, все довольны. Зависимости явные и подмена класса происходит легко:

<?php
namespace Application\HelloBundle\Controller;
// use a custom Controller class instead of the framework's Controller
use Application\HelloBundle\Tools\Controller;

class HelloController extends Controller
{
  // same code as before
}


Конец все удобствам.


Использование use в предыдущем примере вам ничего не напоминает? Это ведь очень похоже на старый добрый require/require_once, не так ли?

<?php
// old style
require_once 'Application/HelloBundle/Tools/Controller.php';
// new style
use 'Application\HelloBundle\Tools\Controller';

Привнесенная неймспейсами многословность в первую очередь снижает легкость использования автозагрузки. Но проблема не только в том, что нужно писать больше кода, в этом вам может помочь IDE с автодополнением, а в том, что вам нужно знать полные имена нужных вам классов. Вы должны очень хорошо знать классы фреймворка, чтобы использовать их. Это шаг назад по сравнению с автозагрузкой “первого поколения”, где было достаточно знать имя класса.

Другого пути нет.


Правда было бы замечательно, использовать современные библиотеки без знания их файловой структуры? Что если бы вы могли написать контроллер так:

<?php
class HelloController extends Controller
{
  public function indexAction($name)
  {
    $author = new Author();
    $author->setFirstName($name);
    $author->save();
    return $this->render('HelloBundle:Hello:index', array('name' => $name, 'author' => $author));
  }
}

Умный автозагрузчик перехватил бы вызов класса Controller, загрузил бы файл Symfony/Framework/WebBundle/Controller.php и динамически создал алиас с Symfony\Framework\WebBundle\Controller на Controller. К сожалению в PHP use создает алиас во время компиляции, поэтому такой ход не сработает. Конечно есть возможность сделать подобное используя eval, но это, наверное, даже хуже, чем подключать файлы вручную. Также создание таких алиасов при работе с фреймворком не возможно по причине конфликта с ленивой загрузкой и конфликта имен классов, например:
Symfony\Framework\WebBundle\Command
и
Symfony\Components\Console\Command\Command
Пока авторы фреймворков не изменят свой взгляд на автозагрузку, будущее PHP мне видится многословным.

Решение проблемы.


Лично я, думаю, что многословность сильно замедляет разработку. Например возьмем микрофреймворки – они дают возможность обработать запрос быстро, при минимуме MVC-разделения. Сравним код примерного приложения написанного с использованием Slim (автозагрузка без неймспейсов) и Silex (автозагрузка с неймспейсами):

<?php
// Hello world with Slim
require_once 'slim/Slim.php';
Slim::init();
Slim::get('/hello/:name', function($name) {
    Slim::render('hello.php', array('name' => $name));
});
Slim::run();

// Hello world with Silex
require_once 'silex.phar';
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Templating\Engine;
use Symfony\Component\Templating\Loader\FilesystemLoader;
use Silex\Framework;
$framework = new Framework(array(
  'GET /hello/:name' => function($name) {
    $loader = new FilesystemLoader('views/%name%.php');
    $view = new Engine($loader);
    return new Response($view->render(
      'hello', 
      array('name' => $name)
    ));
  }
));
$framework->handle()->send();

Во втором примере, автозагрузка делает все только сложнее.

Разработчики современных фреймворков объясняют, что многословность – это цена, которую мы платим за качество кода. Я не уверен, что хочу платить эту цену. Я не хочу видеть как PHP превращается в Java, где код превосходен с точки зрения Computer Science, но очень затратен в написании. Это побуждает желание к использованию других языков, где вопрос автозагрузки с неймспейсами не стоит и при этом, быстрая разработка возможна.

Возьмем например Ruby. Существует такой фреймворк как Sinatra, используя который HelloWorld-приложение становится очень лаконичным:

require 'sinatra'
require 'erb'
get '/hello/:name' do |name|
    @name = name
    erb :hello
end

Ой, смотрите, здесь же используется require! И при этом, все пишется очень быстро и легко в использовании.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 116

    0
    Качество большинства библиотек всегда было не на высоком уровне. Может хоть теперь что-то изменится.
      +5
      Стоит наверное отметить, что хотя use и находится в том же месте, где раньше был require, он несёт совершенно иной смысл, а именно указывает, какой конкретно класс мы хотим использовать в качестве контроллера в данном неймспейсе.
        +6
        Привнесенная неймспейсами многословность


        Разве?

        Zend_Cache_Backend_Memcached vs \Zend\Cache\Backend\Memcached
          +1
          Второй вариант длиннее на символ)
          хотя ИМХО, если бы смотрели в стороне гемов, обозвали бы \Zend\Cache\Backend\Memcached как «will_memcache», «memcahappy», выложили как независимую библиотеку, или ещё как нибудь, и короче было был.
            +2
            А:
            $memcached1 = new Zend_Cache_Backend_Memcached;
            $memcached2 = new Zend_Cache_Backend_Memcached;
            $memcached3 = new Zend_Cache_Backend_Memcached;
            

            и:
            use \Zend\Cache\Backend\Memcached;
            $memcached1 = new Memcached;
            $memcached2 = new Memcached;
            $memcached3 = new Memcached;
            
              +1
              ага, Зенд назвал класс will_memcache. Пришла Симфония — ну ок, будет у нас sf_will_memcache. Пришел еще десяток разработчиков — получили хаос.
              +1
              Такой проблемы, например, в Symfony 1.x не было
                +1
                Зато была проблема того, что ты точно не знал какой именно класс вызовется у тебя.
                  0
                  Все классы Symfony имеют префикс sf. Если знаешь минусы, можешь использовать их как преимущества. А писать километровые имена классов для простоты автолоадера, ИМХО очень «эгоистично» со стороны разработчиков Zend-а.
                    0
                    Согласен, самого напрягали полотна классов ZF. Но по имени класса в ZF, можно было определить к какому компоненту он относится. Теперь есть namespace. :)
                      0
                      Вообще говоря это требования (соглашения?) PEAR. Не только ZF этим страдает. PHPUnit например тоже: $metaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($tableName, $columns);
                        0
                        А у ZF есть официальный pear канал? :)
                          0
                          А причём тут есть или нет? Они следуют их соглашению.
                            0
                            Я то думал они следуют этому соглашению.
                              0
                              Какая разница чему конктрено следуют, если результат один — "_" в именах классов преобразуется в DIRECTORY_SEPARATOR пути к файлу и наоборот.
                        0
                        а кому-то может удобно знать к какому модулю относиться класс

                        это дело вкуса
                          0
                          Согласен, но все равно не удобно. Имея grep я за «пару секунд» узнаю к какому модулю относится класс.
                            0
                            А если, не дай бог, на винде придётся правки вносить? cygwin ставить? :)

                            На самом деле не для удобства автолоадера это сделано, а для удобства клиентов (разработчиков) — знать где какой класс искать без grep'а и как свои именовать и куда их складывать, чтобы другие с первого взгляда (а не с «парой секунд» и grep'ом) могли понять, что где находится. Автолоадеру проще было бы работать с хэшем 'имя класса' -> 'путь'. Но вот нужно вам в своё приложение включить только часть ZF (как это обычно и бывает, связанность у модулей очень низкая в ZF) — полезете в автолоадер или grep запускать, чтобы узнать какие файлы вам нужно в свой проект скопировать? А если этих файлов с десяток-другой-третий? Но у всех один префикс третьего уровня? Уже «минута» только чтобы их найти, а нужно ещё и скопировать.
                              0
                              Никто не запрещает делать логическую структуру директорий и при этом использовать короткие имена классов.
                              К примеру Symfony 1.x, каждый плагин имеет свой префикс (обычно 2 символа) и свою директорию.
                              И найти все получается достаточно просто.
                                0
                                Мне это было неудобно. На ZF с тоской смотрел в этом плане.
                            0
                            Я бы не сказал, что дело вкуса. Дело, скорее, стандартизации, единого подхода. И разграничения ответственностей и инкапсуляции.
                            0
                            Зато сразу понятно, что это за класс, а автоподстановка в любой IDE позволяет набирать имена классов любой длины.
                            После PHP с Zend Framework-ом и Autoloader-ом трудно привыкнуть к хитросокращённым названиям классов в других фреймворках и языках :)
                              0
                              Обычно в начале любой книге по программированию написано, что имена переменных должны быть максимально краткими и нести максимальную смысловую нагрузку.
                              Почему-то никто не пишет
                              $product_That_Need_To_Be_Added_To_Shopping_Cart = ....;

                              Я конечно утрирую, но смысл тот же
                                0
                                Покажите мне эту книгу, пожалуйста.
                                Наверное, она из тех времён, когда имя файла не могло быть длиннее 8 символов, и имена баз данных и таблиц не должны были превышать 4 символа в длину :)

                                И как назвать класс Zend_Db_Adapter_Abstract? zf_dbadpabst?
                                  +1
                                  Как минимум выбросить слово Abstract. zfDbAdapter
                                    0
                                    А как тогда назвать не абстрактный класс Zend_Db_Adapter, если вдруг такой будет? И как отличать абстрактный класс от класса с имплементацией? И что там с книгой?
                      0
                      У автозагрузки есть один большой плюс.
                      Вы можете реализовать в атозагрузчике сборку всех классов в один файл. И потом подключать его одним require. Профит
                        +1
                        Можно поподробнее? У меня при включенном акселераторе (apc.stat=0) не заметно никакой разницы.
                          0
                          У меня включение одного файла со всеми используемыми классами (примерно 3 Мб) с acp.stat=0 дало ускорение в 2-2.5 раза
                            0
                            Интересно, прибавка приличная. Проект на Симфони2? В автозагрузчике используется is_file (ClassLoader) или isset classmap (MapClassLoader)?
                              0
                              Проект на симфони компонентах. У меня автозагрузка через include_path реализована. Т.е. я явно не занимаюсь поиском файла и проверки на его существование
                                0
                                Понятно, спасибо. У меня на карте с полными путями. Возможно, эффект наблюдается когда очень много кода. Надо будет позже протестировать.
                                  0
                                  Т.е. у меня реализована след образом. Автолоадер с начала отсеивает классы которые не нужно паковать — это в основном классы моделей Доктрин ибо там свои приколы с парсингом неймпспейсов, далее заменяет константы типа __FILE__ на соотв. пути, добавляет класс в общий файл, чистит apc кеш ибо в противном случае получим бесконечное разбухание файла классов.

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

                                  Но поработать напильником пришлось. Особенно с путями и некоторыми и доктрин моделями
                                    0
                                    Интересное решение. А можно реализацию где-нибудь увидеть, например на гитхабе?
                      +7
                      Java тут совершенно не причем. Просто PHP движется к enterprise миру, где затраты на написание составляют лишь мизерную часть проекта. Это и не хорошо, и не плохо. Просто нужно понимать где и когда какой фреймворк использовать и использовать ли их вообще.
                        0
                        Вы действительно считаете, что наличие длинных неймспейсов делает ту или иную технологию уровня enterprise?
                          +5
                          Я где-то писал только про namespace'ы? Я смотрю в целом на развитие фреймворков и самого языка.

                          Имхо, двигаться в сторону enterprise — логично. Ибо это даст поддержку крупных и надежных работодателей. Что повысит потенциальные з/п, что повысит престижность языка.
                            +1
                            Но для этого надо быть не «как джава», а быть «лучше джава».
                            А пока только копируются существующие в джава решения, но там они были вызваны особенностями технологии, а в PHP внедряются «потому что это энтерпрайз».

                            Как бы не вышло так, что PHP и сегмент простых, легких применений потеряет, и до энтерпрайза так и не доберется.
                              +2
                              В чём-то уже лучше. Или ещё? :-/ Одним из главных преимуществ PHP всегда было, имхо, простота развертывания приложения. Тем более возможностей писать «спагетти» никто (пока?) не отнимает.
                                0
                                С ужасом жду тех дней, когда программы на PHP будут компилироваться :)
                                  0
                                  Если прозрачный JIT, то почему нет? А так они и сейчас компилируются в байт-код, а с акселераторами и JIT получается.
                                    0
                                    Не получается, и не получиться, пока полноценного JIT-компилятора не будет у PHP. А его не будет там никогда.
                                  –2
                                  Простота развертывания? А как же 100500 параметров, задающихся через ini-файлы?
                                    0
                                    Это уже тюнинг :) Если что я имею в виду Debian-based дистрибутивы Linux и LAMP.
                                      0
                                      Не всегда это тюнинг. Создателям php долго доказывали, что задание в настройках register globals и magic quotes — зло, и они это поняли. Но почему-то до них не доходит что задание любых настроек в общем случае — зло, ведь от этих настроек зависит работоспособность кода, а значит код перестает быть самодостаточным.
                                +1
                                Да, сам язык такой ентерпрайс… Без много поточности, без нативной поддержки utf, без возможности писать что-либо серьезное помимо веб-приложений. Python и Ruby гораздо больший ентерпрайс, но почему-то вот не пытаются копировать в себе Джаву. При этом, есть и JRuby, IronRubym JPython,… То есть эти языки поддерживаются на ентерпрайс уровне без каких-либо синтаксмических или фреймворковых нововведений.

                                Если вы считаете, что наличие аннотаций, dependency injection, namespaces делает язык ентерпрайсом вы крайне ошибаетесь. Это просто независимые вещи. А вот то, что PHP в гонитве за статусом и пытается стать недоджавой, это печально.
                                  0
                                  Прочтите мой коммент внимательно. Там только, по сути, про «пытается стать недоджавой» и написано. Только другими словами. Да, наверное, моя ошибка в том, что недостаточно раскрыл мысль.

                                  ЗЫ: Лично я к PHP отношусь очень прохладно и пишу на нем только потому что *пока*что* мой основной заработок идет именно с него. Но это не тема этого обсуждения.
                                    0
                                    Ну тогда ок, почти коллеги )
                                    Мне вот не нравится, что игнорируя все хорошие фишки РНР сообщество пытается создать некую видимость ентерпрайса. Конечно, хорошо, что библиотеки становятся стандартизироваными, чем-то похожими, но плохо, что количество фреймворков до сих пор не дает нужную легкость в разработке.
                                      0
                                      О. Не один я такой. Заказчики люди консервативные и любят php.
                                        0
                                        Кроме того заказчики ещё люди рациональные — они учитывают не только стоимость разработки, но и развёртывания, администрирования и поддержки (кода). Почему-то за развёртывание, например, rails приложения на «голом» Линуксе админ-фрилансер или саппорт (в)дс-хостинга берёт больше, чем за развёртывание приложения на PHP(+ZF/Yii/Symfony/...). Меня неоднократно на хабре пытались убедить, что приложение под рельсами развернуть чуть ли не проще чем на голом пхп. Если так, то почему дороже?
                                          0
                                          куда уж легче чем на lamp :)
                                            0
                                            Я тоже так считаю. Причём считаю это куда большим плюсом PHP, сыгравший, вкупе с грубо говоря $_*, на его популярности больше, чем Си-подобный синтаксис и встраивание в HTML вместе взятые.
                                            0
                                            Смотря где. С появлением Heroku многие хостеры выпускают свой гем для быстрого развертывания приложения. Например, я использую Webbynode, там развертывание и деплоймент это одна команда и практически без настройки.
                                              0
                                              Универсального способа нет. С PHP все знают, что переезд с хостинга на хостинг практически без проблем происходит. С rails сложнее вроде как. С heroku же на Webbynode не переедешь правкой одной строчки? Да и ВДС/облака сейчас популярны.
                                                0
                                                Если в PHP всё так офигенно, то почему для Symfony столь популярен capifony — Capistrano + Symfony capifony.org/. Наверное, потому что деплоймент не столь простой, это раз. И наверное потому, что тулза написана на руби не имеет аналогов на PHP.
                                                  0
                                                  Использование Capistrano (я «нативным» пользуюсь) дает лишь удобство задеплоить всё одной командой, да ещё из репов, с версионностью, откатами и миграциями БД. В принципе я пользовался для symfony-проектов и bash-скриптами с rsync для файлов и ssh для остановки/старта сайта (поле в БД), миграций (можно было и без него, но не хотелось мускул наружу открывать). А аналоги есть на PHP, Phing, например, или WePloy. Capistrano просто удобнее благодаря сахару Ruby. Что не говори, а Ruby приятный язык, даже (тем более?) если не использовать «манкипатчинг» :)

                                                  А под развёртыванием я имел в виду не только, и даже не столько деплой собственно приложения, но и развертывание среды выполнения. То есть, есть свежеустановленый дистр Линукс, к которому у нас консоль или ssh/ Нужно развернуть на нём всё для деплоя рельсового приложения, да не одного, а на нескольких на виртуальных хостах. Для PHP два с половиной варианта по сути (apache + mod_php + возможно ngnix, и nginx + php-fpm), всё ставится из реп (Debian и Ubuntu имею в виду), можно из родных, можно с dotdeb и т. п. Установка — одна строка, апдейт — две строки вместе с апдейтом всей остальной ОС. В крайнем случае за PEAR надо следить, PECL на практике не встречал. C рельсами же всё сложно, особенно если хочется соблюсти debian-way и ставить всё из пакетов. Хотя пока писал коммент, обнаружил, что на dotdeb теперь и passenger есть, и ruby 1.9.3 в репах debian. Надо будет ещё раз попробовать установку провести, может без компиляции удастся установить всё.
                                                    0
                                                    Phing это ж вообще не то… А вот за WePloy спасибо, посмотрю.

                                                    Насчет, debian way, то его всё-таки стоит нарушить и поставить ruby 1.9.3 через rvm. Это наверное, единственное, что нельзя поставить из пакетов.
                                                      0
                                                      Для PHP два с половиной варианта по сути (apache + mod_php + возможно ngnix, и nginx + php-fpm),

                                                      Как минимум, есть еще uWSGI, который с недавних пор также умеет php.

                                                      NGINX + uWSGI
                                                        0
                                                        Как-то пропустил эту новость.
                                      0
                                      namespace, type hinting и прочие плюшки которые имеются у энтерпрайз языков, действительно облегчает использование языка в этом самом энтерпрайзе. Потому что там кроме «написали и в продакшн», есть еще долгая-долгая история в виде «поддерживаем» и «допиливаем». Да и зачастую над проектом работают не пять человек, а 25 или 50, или того больше.
                                        0
                                        С другой стороны, возможность их не использовать увеличивает разрыв между «написали и в продакшн» (как мне тут написали на днях «сайтостроителями») и «энтерпрайзом». Переход разработчика в другую «лигу» затрудняется. Сделать их обязательными — повысим порог входа и привлекательность для разработки простых сайтов и приложений.
                                    –8
                                    Тоже мне проблема, которая «побуждает желание к использованию других языков»! Не нравиться? Не пиши на PHP!

                                    Это не статья а очередной шлак очередного нытика. На ныл на целую статью, а «Решение проблемы» так и не предложил. Да и проблему то, назвать проблемой сложно.
                                      –3
                                      ТОЛЬКО ХАРДКОР ТОЛЬКО ПЭХАПЭ
                                        0
                                        Это шутка? Сарказм? Что за идиотский комментарий?
                                      • UFO just landed and posted this here
                                        +2
                                        думаю автокомплит поможет. мы также не помним имена всех классов.
                                        use [ctrl+space] и выбираем себе нужный namespace
                                          +2
                                          Реально надуманная проблема. Пользуюсь нормальной IDE и вообще никогда не парился по поводу неймспейсов )
                                            +1
                                            что-то в этом есть
                                              –1
                                              Ну как бы проблема пока есть. Например, вводишь название класса Command. Он раскрывается в длиннючую малочитабельную строку \Symfony\Component\Console\Command\Command.

                                              Альтернатива — прописовть все используемые классы в начале файла. Но это шаг назад, имхо.
                                                +1
                                                У меня IDE пишет только Command а в начало файла автоматом дописывает
                                                use \Symfony\Component\Console\Command\Command
                                                IDE — PhpStorm
                                                  +1
                                                  Хотя могу ошибаться… Видите, для меня почему-то это настолько несущественно что я даже не помню как оно точно происходит )
                                                  0
                                                  Это ведь проблема не языка, а IDE.
                                                    0
                                                    Та нет, проблема языка, ибо всё равно дописывается вверх класса

                                                    use \Symfony\Component\Console\Command\Command.

                                                    Малозначащая и бессмысленная лишняя строка. И таких будет много.

                                                    Я к тому, что, как минимум вариант

                                                    use \Symfony\Component\Console\*

                                                    нужно было предусмотреть.
                                                      0
                                                      use \Symfony\Component\Console;
                                                      
                                                      $cmd = new Conslole\Command\Command();
                                                      
                                                      равносильно
                                                      use \Symfony\Component\Conslole\Command;
                                                      
                                                      $cmd = new Command();
                                                      
                                                      или
                                                      $cmd = new \Symfony\Component\Console\Command\Command();
                                                      

                                                        0
                                                        Да, но почему вот нельзя ввести * для вгрузки классов из неймспейса, а не перечислять их каждый по очереди.
                                                          +2
                                                          Уже третий раз коммент заново начинаю писать :) Всё не могу понять что же должно произойти при use \Symfony\Component\Console\*.
                                                            0
                                                            Импорт всего, что только модно из этого пакета, естественно! Что бы не наблюдать простыню из:

                                                            use some\package\name\A;
                                                            use some\package\name\B;
                                                            //…
                                                            use some\package\name\Z;

                                                            А видеть одну замечательную строчку:

                                                            use some\package\name\*;
                                                              +1
                                                              В текущей модели autoload это практически невозможно, не говоря о том, что use к импорту отношения не имеет, это скорее define. Сомневаюсь, что это вообще возможно в рамках нынешней работы autoload, в котором местонахождение источника кода класса и даже его физическая сущность никак не связаны с его полным именем. По крайней мере в лоб я вижу решение только на уровне языка связывать полное имя и физическое местонахождение. То есть не на уровне соглашений решать, что some\package\name\Z лежит в файле <include_path>/some/package/name/Z.php, а на уровне интерпретатора. Небольшой модификацией (ака костыль) может быть получится, если передавать в autoload список объявленных в данном контексте префиксов, а та будет пытаться перебирать сочетание префикс+класс до первого совпадения, но что-то такой костыль такая перспектива не радует — статический анализ ошибки не выявит.
                                                                0
                                                                Все реализуемо. Единственная проблема — велосипедисты, которые считают, что следование стандартов очень уж загоняет их тонкую натуру в жесткие рамки.
                                                                  0
                                                                  Понятно, что реализуемо, но, по-моему, если реализовывать хоть с намёком на обратную совместимость, то оно того не стоит. Ради того, чтобы писать use some\package\name\* и использовать $a = new A; class ZZ extends Z {} вместо use some\package\name и $a = new name\A; class ZZ extends name\Z, жертвовать производительностью, да и стабильность как-то…

                                                                  Другое дело если полностью забить на совместимость и сделать практически также как в питоне, чтобы use была именно импортом, а не «директивой препроцессора», то есть изменить семантику, а не просто синтаксис расширить. Совместить нынешнюю функциональность use и require. Или оставить use для выполнения кода для PHP версии меньше 6 :), а сделать import, которому не потребуется autoload, максимум (чтобы в рамки не загонять) потребуется какая-то функция вроде autoimport.
                                                                    +1
                                                                    use и autoload это две разные, никак не связанные вещи.

                                                                    use, да и вообще весь механизм пространств имен нужен для облегчения жизни разработчику. Например, не писал по 20 раз в одном файле полное название класса\функции, а использовать для нее алиас. Или для разруливания конфликта имен, из за того что у нас есть my\super\puper\xml\Parser и my\mega\cool\json\Parser.

                                                                    Все, добавление сюда звездочки говорит препроцессору (или что там у пхп с юзом работает), что у нас 100500 классов юзаются из пакета my\some\package и надо оставить это связывание для рантайма (по другому просто никак) а уже в рантайме мы дергаем другой клевый механихм, называемый автолоадом,

                                                                    А автолоад — это когда интерпретатор понимает что запрашиваемого класса у него нет и поэтому он передает управление коллбекам с параметром — а ну-ка найди мне «some\package\name\A», ни один из коллбеков не вернул класс, ну что же, значит пичалька.

                                                                    В той же яве все тоже самое, классы подгружаются по мере надобности, да и если что, можно за пару-тройку вечеров написать свой клевый класслоадер который будет на лету подхватывать проект, перекомпилировать измененные классы и перегружать их в рантайме.
                                                                      0
                                                                      Так я и говорю, что use со звёздочкой потребует модернизации механизма autoload. Нельзя говорить, что они никак не связаны. Препроцессор оставит рантайму, а рантайм без модернизации не будет знать какие неймспейсы определены для данной строчки с new, extends и т. п. Модернизируя autoload (передавая ещё одним параметром список «открытых» неймспейсов), мы обрекаем его на перебор с возможностью как не получить совпадения, так и получить два и более совпадения. Первое ладно, а вот со вторым что делать? Да и вообще перебор не есть гуд, имхо.

                                                                      Вот вариант типа use \Symfony\Component\Console\Command\[Command,HelpCommand,ListCommand] никаких изменений в autoload не потребует, просто сахар. А в том же python import * тоже не рекомендуется видимо по схожим причинам.
                                                                        0
                                                                        Прочитайте, пожалуйста, еще раз мой комментарий, и еще раз, как работает автолоадинг на сайте php.net. Ничего там менять не придется.

                                                                        Подставьте в ваш пример вместо списка классов звездочку и будет все тоже самое.
                                                                          +1
                                                                          Пойду почитаю, а вы подумайте, что должно передаться в autload при выполнении следующего кода:
                                                                          use /ns1/sub1/*;
                                                                          use /ns1/sub2/*;
                                                                          use /ns2/sub1/*;
                                                                          use /ns2/sub2/*;
                                                                          
                                                                          $obj = new SomeClass();
                                                                          

                                                                          На этапе «компиляции» у PHP нет никаких сведений о том, что может находиться в неймспейсах. Что он должен передать текущей реализации autoload, если класса или алиаса SomeClass он ещё не знает?
                                                                          /ns1/sub1/SomeClass? /ns2/sub2/SomeClass?
                                                                          Или 4 раза дёрнуть autoload с /ns1/sub1/SomeClass, /ns1/sub2/SomeClass, /ns2/sub1/SomeClass, /ns2/sub2/SomeClass. А если где-то конфликт выскочит то с ошибкой вылететь?
                                                                            –1
                                                                            Ну вот, сам ответил на свой вопрос :)
                                                                              0
                                                                              Так перебор же. Считаешь нормально это?
                                                                                –1
                                                                                Ну автолоад сам занимается например перебором всех доступных колбек функций. В одном проекте может быть много автолоадеров, каждый от своей библиотеки. И для поиска одного класса дергаются они все.

                                                                                Если два похожих автолоадера дергаются для поиска одного класса, то в чем это отличается от предложенного варианта? Дергать один автолоадер, но с другими параметрами.
                                                                                  +1
                                                                                  Точно, значит если 4 автолодера и 4 use *, значит дёргаться будет 16 раз :)
                                                                              0
                                                                              Нужно просто избегать такой код, а не выяснять что пойдет не так.
                                                                    0
                                                                    Ну да, use к autoload не имеет отношения. Так это отлично.

                                                                    Если в коде находится неизвестный класс, PHP пытается найти его в рамках используемых неймспейсов. Он последовательно перебирает все неймспейсы со звездочкой, подставляя вместо звездочки искомый класс.
                                                                      0
                                                                      И каждый раз вызывает autoload? Ведь только она знает где и как физически находится класс.
                                                    +5
                                                    Никто ведь не заставляет писать use Application\HelloBundle\Tools\Controller; class HelloController extends Controller { //... } Можно обходиться и class HelloController extends \Application\HelloBundle\Tools\Controller { //... }. В данном контексте use лишь средство DRY, не?

                                                      +1
                                                      Пространство имен отождествляемое с include, в коментах подключение всех файлов в комментариях… Ну-ну.

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

                                                      Судя по статье и комментариям люди ленятся прописывать лишнюю строчку сверху, при этом обожают копипастить одинаковый код снизу, или же никогда не работали с проектами огромных объемов.
                                                        0
                                                        А где про копипастить? :)
                                                          0
                                                          В голове тех, кто не понимает зачем создали пространство имен. Его же не ради прикола ввели в php, а чтобы была возможность еще больше стандартизировать взаимодействие с классами и процесс разработки, тем самым уменьшив время разработки и кол-во кода.
                                                          0
                                                          А чем именно вам не нравится симфа2? Мне тоже по-началу не нравилась, возможно тем что «слишком много нового», но теперь привык и уже как то ломает возвращаться к первой на некоторых проектах.
                                                            0
                                                            Вот только прямой связи между способом подключением плагинов и неймспейсами никакой нет.
                                                            +2
                                                            > Это ведь очень похоже на старый добрый require/require_once, не так ли?

                                                            Оператор use не вызывает автолоадер, только создаёт алиас в памяти на будущее.

                                                            > К сожалению в PHP use создает алиас во время компиляции, поэтому такой ход не сработает.

                                                            class_alias() решает эту проблему. Но зачем?

                                                            Использую use по следующим причинам:
                                                            1. Сразу видно от чего зависит данный класс
                                                            2. Во время разработки можно переключить на «подобный» класс изменив всего лишь use
                                                              +1
                                                              Можно вместо use везде использовать полные имена, в таком случае класс подгрузится автоматически.

                                                              // Hello world with Silex
                                                              require_once 'silex.phar';
                                                              $framework = new Silex\Framework(array(
                                                              'GET /hello/:name' => function($name) {
                                                              $loader = new Symfony\Component\Templating\Loader\FilesystemLoader('views/%name%.php');
                                                              $view = new Symfony\Component\Templating\Engine($loader);
                                                              return new Symfony\Component\HttpFoundation\Response($view->render(
                                                              'hello',
                                                              array('name' => $name)
                                                              ));
                                                              }
                                                              ));
                                                              $framework->handle()->send();


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

                                                              А в целом Silex так организован тк. базируется на Symfony, где подобные загрузчики необходимы из-за проблем в поддержке большого кода.
                                                                +1
                                                                некоторые скажут, что так зависимости более очевидны для разработчика

                                                                Некоторые даже скажут, что это конвенция.
                                                                  +1
                                                                  Я за подобные конструкции, просто автор ругается на них и я показал другой путь :).

                                                                  P.S. Вы промазали ;).
                                                                    0
                                                                    Вечно промазываю когда на последний коммент в посте отвечаю :(
                                                                  0
                                                                  Мне кажется, что с неймспейсами в IDE будет реализовать поиск зависимостей.
                                                                    0
                                                                    Для поиска, вернее управления зависимостями и пакетами есть другие инструменты: классический PEAR, модный composer (рекомендую).
                                                                • UFO just landed and posted this here
                                                                    0
                                                                    > Использование use в предыдущем примере вам ничего не напоминает

                                                                    Ога. Напоминает. Инклуды в C/C++, Import в Java… продолжать?
                                                                    • UFO just landed and posted this here
                                                                        0
                                                                        Cкорее #define

                                                                        use /A/B/C;
                                                                        $o = new C/D();


                                                                        что-то вроде

                                                                        #define C /A/B/C
                                                                        $o = new C/D();

                                                                        0
                                                                        Атор пишет эпический бред. Кладем всю библиотеку в один неймспейс, пишем, к примеру:

                                                                        use \AdvancedORM;

                                                                        Получая и автозагрузку, и разделение пространств имен, и избавивляясь от педантичности Явы. Если у кого-то настолько мало мозгов, что он каждый класс кладет в свой неймспейс, то это уже его проблемы.
                                                                          0
                                                                          Извините, автора я уважаю, ибо он в отличии от многих РНР разработчиков не пытается копировать яву или руби, а занимается развитием самобытного ORM Propel. По многим вещам пропел уже удобнее даже Rails ActiveRecord, не говоря уже о Доктрине.

                                                                          А теперь про эпический бред.
                                                                          Кладем всю библиотеку в один неймспейс

                                                                          Вот это как раз эпический бред. Можно с таким же успехом написать: неймспейсы в PHP опциональны, не нравится — не используйте. Но никто не говорит, что они не нужны. Просто их нынешняя реализация это шаг назад в удобстве и шаг вперед в улучшении качества кода. Опять таки, оператор * из той же Java был бы совершенно не лишний и в РНР.
                                                                            0
                                                                            Эпический бред пишите вы. У меня сейчас (я сейчас пишу на яве) в проекте более 200 различных пакетов, скажем так, первого уровня, com.company.product. и в которых может доходить до десятка подпакетов, в пакетах в основном не больше 3-8 классов. Знаете, когда у меня возникают трудности? Никогда, т.е. когда я в текстовом редакторе поправлю название какого-нибудь класса, а потом забуду о том, что надо еще залезть в первые строчки файла и там поправить название пакета.

                                                                            Пакеты и автоматическая работа с ними — это хорошо и прекрасно. Я могу хорошо все разложить и в 3-5 кликов быстро найти нужный мне компонент, если поиск по названию класса мне не помогает.

                                                                              0
                                                                              А FatalError не вызовет, если писать после этого $table = new Table(); вместо $table = new \AdvancedORM\Table();? Или это чтобы писать $table = new AdvancedORM\Table();, то есть экономить один бэкслэш?
                                                                              0
                                                                              Автор молодчина. Ведь в который раз велосипед изобретается?!

                                                                              Only users with full accounts can post comments. Log in, please.