Pull to refresh

Comments 25

Тут обновление, там обновление… эх где бы найти столько времени, чтобы успевать за всеми обновлениями.
Мне конечно симфони интересна, но вот это совсем уж круче вареных яиц:

use Symfony\Component\PropertyAccess\PropertyAccess;


Это так стандарты PSR-N советуют? Нафиг нафиг такие стандарты. Какая двухсмысленноть и тавтоглогия. Сдается мне все это как хомут следования сомнительным стандартам.

надо было хотя-бы так написать:
namespace symfony\сomponent;

class PropertyAccess
{
...
}




а потом:
use symfony\component;

...
component\PropertyAccess
Это соглашение о правиле создания Namespase в Symfony 2.
Если в каком то случае получилось не совсем красиво, то не думаю что нужно сразу об этом кричать.
Двойное PropertyAccess они не советуют прямо, но совпадение имен компонента (последня часть нэймспэйса) и его «главного» класса принято не просто так. Нэймспэйсы транслируются на ФС и классу Symfony\Component\PropertyAccess\PropertyAccess соответствует файл Symfony/Component/PropertyAccess/PropertyAccess.php если мы захотим добавить какой-нибудь служебный класс или интерфейс типа Symfony\Component\PropertyAccess\ObjectAccessor, то весь компонент Symfony\Component\PropertyAccess будет лежать в одном каталоге, а не часть в файле в Symfony/Component/PropertyAccess.php, а часть в файлах Symfony/Component/PropertyAccess/*.php — видал я системы по такому принципу сделанные: очень неудобно, то «главный» файл забудешь скопировать, то каталог, а тут одним махом полностью компонент. Можно, конечно, главный класс назвать не так как компонент (зачастую так и делают), но чаще удобно именно продублировать. Опять же отчасти потому что принято писать полный путь в use, а в new и т. п. только имя класса. Прямых требований вроде нет, но так удобнее.
Оно понятно что это дань автозагрузчику классов, вычисляющиего по сигнатуре полного имени класса его точный путь, но иногда бывает очень удобно разместить те-же интерфейсные классы прямо в том же файле, где объявлен класс. На практике получается, что в таком модуле могут содержаться (или логично или так хочется) несколько связанных классов Создавать еще один файл ради того чобы туда поместить интерфейс или подкласс Exception занятие утомительное и отвлекающее. Весь компонент может уместиться в одном модуле, если он получается не более 600-700 строк кода.

Решить проблему загрузки классов можно явным указанием статического списка классов, которые в свою очередь при старте будет добавлен к автозагрузчику классов. Есть несколько утилит, генерирующий модуль автолоад всех зависимых классов.
Что же такого отвлекающего и утомительного, особенно при наличии автозагрузчика? Создать файл? Скорее уж утомительно потом лазать по файлу и искать где же нужный класс. Или при необходимости использовать такой второстепенный класс вне основного — автозагрузчик не сработает >> выскочит ошибка >> догадываемся «ага, значит не вынесен класс» >> залезаем в библиотеку, выносим в отдельный файл (или есть альтернативная реальность в которой мы инклудим нужный нам файл, но предположим что мы все-таки хотим пользоваться автозагрузкой) >> и если это самопальный одноразовая библиотека, то радуемся жизни (но что-то не похоже это на упрощенный подход).

Существуют еще версии:
— это n-ая итерация и мы играем в игру «из какого же файла выносить»;
— эта библиотека лежит в репозитории и мы делаем весьма забавный коммит (или еще смешнее, пулл реквест, а если не примут, тогда форк).
Штатный автозагрузчик по маппингу имен классов делает свою работу относительно хорошо. Но за это приходится платить дублированием имен и довольно приличной вложенностью папок. Это больше похоже на машиночитаемый формат. Кстати, размышляя на эту тему увидел интересную аллегорию с классами и ЧПУ. Что-то в этом есть…

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

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

На мой взгляд, зачем без особой необходимости создавать еще лишние сущности — лучше держать все рядом. Так нагляднее и проще. Особенно это актуально при непосредственной разработке компонента. Да, согласен, что как только классов становится много — такой модуль придется «расшивать», но это обычно уже характерные архитектурные проблемы и антипаттерны. Типа класс слишком много на себя берет. Кстати так легче отследить «точку перегиба», когда число сущностей необоснованно растет.

Насчет «искать где нужный класс» — в общем да, по имени модуля найти класс относительно легко, если не принимать во внимание вложенности папок (нужные классы живут в дремучих лесах). Но обычно это проблема качественной диагностики обработчиком ошибок: имя модуля, класс, строка, ошибка. Когда это работает правильно — локализовать ошибку легко. Есть еще удобное средство поиска git grep, git ls-files рекомендую к использованию.

Существуют еще версии:
— это n-ая итерация и мы играем в игру «из какого же файла выносить»;
— эта библиотека лежит в репозитории и мы делаем весьма забавный коммит (или еще смешнее, пулл реквест, а если не примут, тогда форк).

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

А при совместной разработке такой подход может быть особенно неприятен — про это второй пункт.

В общем, совсем маленькую библиотеку, без какого-либо потенциала для развития, и которой никто больше точно не будет пользоваться, еще можно так реализовывать (все в одном файле). Но зачем себя к такому приучать, если придется переучиваться при разработке чего-то более серьезного?
теперь понятно о чем — благодарю за разъяснения.

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

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

Возможен такой хинт: так как такое бывает не часто, то в случае ошибки автозагрузчик открывает все не открытые модули для данного уровня пространств имен.
Дублирование имен модуля и его главного класса дань не столько самому автозагрузчику или IDE, а «менеджеру пакетов», в роли которого частенько выступает человек, которому удобно «пакет — каталог». Хотя, можно было бы позаимствовать концепцию загрузки из python (вроде) и избежать дублирования с помощью файла с предопределенным именем. То есть класс Symfony\Component\PropertyAccess хранился бы в Symfony/Component/PropertyAccess/__main.php, а
Symfony\Component\PropertyAccess\ObjectAccessor в Symfony/Component/PropertyAccess/ObjectAccessor.php или Symfony/Component/PropertyAccess/ObjectAccessor/__main.php на выбор разработчика.

Несколько классов/интерфейсов в одном файле — это другая проблема. Бывает, конечно, желание интерфейс или value object описать в одном файле с основным файлом, но поддержка этого статического списка как-то пугает, пускай и с утилитами. К идее «один класс или интерфейс — один файл c однозначным соответствием имен» я пришёл ещё во времена PHP4. Длинный список require_once 'module_class' с явными зависимостями для каждого используемого класса каждого используемого модуля мне показался более предпочтительный в плане поддержки чем по несколько require_once 'module_submodule' без явного соответствия submodule и имен классов. Хотя, с помощью питоновской системы и это, наверное, можно было решить.
а «менеджеру пакетов», в роли которого частенько выступает человек, которому удобно «пакет — каталог». Хотя, можно было бы позаимствовать концепцию загрузки из python (вроде) и избежать дублирования с помощью файла с предопределенным именем. То есть класс Symfony\Component\PropertyAccess хранился бы в Symfony/Component/PropertyAccess/__main.php,

Собственно менджера пакетов как раз и не хватает. Вы правильно заметили, что в качестве оного выступает человек. В симфони и PSR, выбран на мой взгляд компромисс между human readable format и программный формат. Но большая вложенность это явный перегиб в сторону программного формата нежели человеко-читаемого + тавтология. Насчет питоновской концепции здравая мысль. Только такое в общем-то уже есть. Называется по другому: вместо __main.php обычно autoload.php, расположенный где-то в известном месте.

К идее «один класс или интерфейс — один файл c однозначным соответствием имен» я пришёл ещё во времена PHP4.

Вы не одиноки в этом — аналогично. Но со временем стало раздражать по каждому чиху создавать отдельный модуль. Нет все держать в одном модуле большее зло — речь идет о разумном компромиссе. С появлением autoload в самом php и spl_autoload все значительно упростилось.

Длинный список require_once 'module_class' с явными зависимостями для каждого используемого класса каждого используемого модуля мне показался более предпочтительный в плане поддержки чем по несколько require_once 'module_submodule' без явного соответствия submodule и имен классов. Хотя, с помощью питоновской системы и это, наверное, можно было решить.

Никаких *_once это только запутывает и усложняет на мой взгляд — все гораздо проще и оптимальнее через одну точку входа на загрузку через spl_autoload.

В идеальном случае include|require сосредоточены только в модулях автозагрузки. Другими словами в прикладном коде нет инклюдов. Это создает некоторую проблему по загрузке чисто функций и просто кода не привязанного к классам, но это решаемо.

Называется по другому: вместо __main.php обычно autoload.php, расположенный где-то в известном месте.

Похоже, не поняли меня. Я лишь про изменение конвенции, изменение логики работы общего для всех autoload, во избежание тавтологии. Namespace\Class ищется в Namespace/Class.php или Namespace/Class/__main.php, что позволяет с одной стороны избежать тавтологии, а с другой держать при необходимости основной и вспомогательные классы компонента в одном каталоге.
Никаких *_once это только запутывает и усложняет на мой взгляд — все гораздо проще и оптимальнее через одну точку входа на загрузку через spl_autoload.

Я про PHP4. :)
насчет мейна после размышлений — в общем оно конечно хорошо, но будет жутко тормозить при проверках. Лучше тогда поменять имя главного класса пакета-компоненты на Main. В этом случае дублирование снимается и все ок.
Тавтология — да, поспорить сложно. Но в чем двусмысленность?

Повторение связано с тем, что по PSR-0 namespace соответствует расположению файла, и последний уровень — это название файла.
Symfony\Component\PropertyAccess\PropertyAccess находится в

Symfony/
    Component/
        PropertyAccess/
            PropertyAccess.php
            ...

Что, в целом, логичнее чем:

Symfony/
    Component/
        PropertyAccess.php
        PropertyAccess/
            ...

Особенно когда в директории Component достаточно много вложенных директорий (а так и есть), решение вынести из каждой по одному файлу не выглядит особо рациональным.

Смысла же в этом не видно совсем:

use Symfony\Component;
...
Component\PropertyAccess

Правда не понимаю чем же такая запись лучше.

По крайней мере, в случае полной записи названия класса в use сразу видны зависимости, а также проще рефакторинг в случае замены класса.
С тавтологией без потери удобства можно было бы бороться чем-то вроде
Symfony/
    Component/
        PropertyAccess/
            __main.php
            PropertyAccess.php


А насчёт второго может быть удобно, если у нас много классов/субнэймспэйсов из Symfony\Component\ используется. Компромисс между полным перечислением в «шапке» и использованием полных имен в коде по читаемости. Хотя с рефакторингом, да, проблемы могут быть, особенно ручным.
Тавтология — да, поспорить сложно. Но в чем двусмысленность?

На мой взгляд двусмысленность или неоднозначность в том, что сложно отличить имя класса от части namespace Лично меня это запутывает. Когда вложенность namespace большая — приходится задаваться всякий раз вопросом: а нет ли такого класса на данном уровне namespace?

Вы правы. Справедливое замечание. Об полной записи класса, зависимостях и наглядности как-то не подумал. Выработалась привычка писать в основном такое клише:
...
use something\somewhere;
...
$ofoo = new somewhere\Foo();
$obar = new somewhere\Bar();
$obaz = new somewhere\baz\Baz();

Согласен, в таком коде несколько сложнее будет отследить явно имя класса. Но это можно легко компенсировать тегами комментариями на диалекте phpdoc/doxygen. Но так более компактно и проще разрешить конфликты имен.

Особенно когда в директории Component достаточно много вложенных директорий (а так и есть), решение вынести из каждой по одному файлу не выглядит особо рациональным.

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

Например типа такой структуры: pear2.php.net/PEAR2_Pyrus_Developer/files
Там более прозрачная структура, хотя и большая вложенность присутствует.

Там такое сплошь и рядом, доведенное до уровня стандарта. Крика никакого нет, но это реальный бред.
Вышел апдейт с таким вкусным списком новых фич, а 90% комментариев про какую-то незначительную фигню. Даже не знаю, смеятся или плакать.
Самое интересное по идее Console и Process, но область их применения весьма слабо пересекается с обычным кругом задач PHP.
Они как раз и помогают расширить этот «обычный круг задач PHP».

А из интересного в непосредственной практике — сразу вот сейчас буду использовать новинки роутинга в Симфони-проектах, PropertyAccess — в старом проекте, который медленно, но верно рефакторю (и явно класс еще не раз пригодится), а Stopwatch — отправляется в дебаг тулкит.
В принципе да, но всё равно как-то для консольных утилит PHP мне последний в голову придёт. Вот сижу думаю почему. Наверное из-за слабой поддержки модульности.

А я как-то не вспомнил, где мне нужна была относительная адресация и, главное, зачем :)
Routing: Поддержка URL-хостов при маршрутизации; — Отлично

Очень рад развитию этого прекрасного фреймворка, теперь любой более менее сложный проект без этого fw кажется пустым )
Sign up to leave a comment.

Articles