Префиксы и постфиксы в PHP (и CSS)
Ещё давно я взял практику использовать префиксы и постфиксы в PHP и в CSS. Особенно это актуально, когда что-то выходит за рамки локальной видимости и находится в глобальном пространстве, взять те же модели в Yii.
Префиксы и постфиксы несут основную задачу — сделать сущность максимально уникальной, причём настолько, чтобы её можно было без проблем найти любым текстовым редактором. На сегодняшний день IDE поддерживают отличную вещь — «Find Usages» (поиск использований), но это не всегда помогает, и об этом я напишу чуть ниже.
Именование в стиле Венгерской нотации мне не пришлось по душе. Такой подход мне не нравился ещё со времён C++ / Delphi — я считал его избыточном и не всегда понятным. Мне понравилась реализация БЭМ, но в полной мере я её тоже не использую. Я постарался вычленить и объединить наиболее понравившиеся мне методы, о них и расскажу.
CSS Все CSS классы я начинаю с префикса «cl_», идентификаторы с префикса «id_». Если класс или идентификатор относится к блоку, добавляю после префикса «b_», если к модулю — «m_». Какие-либо внутренние состояния или мини-блоки я также указываю с префиксами. .cl_b_promoblock {} #id_m_user_list {} #id_m_order_preview .cl_b_user_info {} .cl_user_list_item .cl_visible {} #id_b_main_menu .cl_main_menu_item.cl_selected {} Таким образом, у меня всегда уникальные и структурно понятные названия. Да и найти такие названия куда проще, если надо, например, провести рефакторинг и посмотреть, где это может отразиться.
Кстати, такой код легче прогнать через сжатие и обфускацию. Причём, не надо никаких анализаторов — ищи регуляркой по префиксам и сжимай. Собственно, поэтому и используются разные префиксы для идентификаторов и классов. Я думаю, статья про сжатие и обфускацию будет интересна аудитории Хабра, постараюсь её оформить, как появится время.
PHP (Yii) Как-то неправильно, что контроллеры, валидаторы и т.п. имеют дополнительные префиксы и постфиксы, а модели не имеют. Я решил, что ввиду «магии» Yii тяжело будет найти, где используется класс User, а простым поиском по тексту слово User будет встречаться везде, где только можно.Поэтому классы моделей именуются как WbUserModel, WbCatalogItemModel и т.п., где:
Wb: идентификатор проекта (сокращение от названия); User: собственно, модель; Model: означает, что это модель, а не что-то другое. Под такой шаблон попали также валидаторы (WbExistsByPkValidator, WbCensureValidator) и собственные вспомогательные библиотеки (LArray, LTime, LString), где префикс «L» — сокращение от Library. Что касается библиотек, то можно использовать также и StringLib или ArrayLib, однако моё мнение — префикс «L» ставит их в списке файлов друг за другом, что удобно. К слову, для методов «scope» я также добавляю префиксы, например, ScopePublished () или ScopeLast (int $limit), чтобы отличать их от «обычных» методов.
Использование таких наименований придаёт уникальности, и в случае чего я могу даже без IDE найти все использования того или иного класса. Также я всячески старюсь отойти от использования текстового представления классов и атрибутов, особенно считаю большим злом, когда ссылка на класс генерируется из объединения строк — это нельзя найти ни через «Find Usages», ни через поиск по тексту. Например:
public function actionGetData ($object_type) { $model_class = 'Wb' . $object_type. 'Model'; $model = new $model_class (); return $model; } Для именования relations в Yii я также использую специальный префикс — «R_» (сокращение от Relation). Таким образом, при взгляде сразу уже понятно, что это не атрибут модели, а именно связь с другой моделью. Хотя по концепции Yii это преподносится как одно и то же (атрибут модели), всё же я считаю, что это разные вещи. Помимо добавления префикса, я всегда добавляю также и название класса модели. Да, этот подход может и менее красив, зато сух и конкретен — при взгляде на код я сразу же понимаю, что от чего зависит, и откуда взялись данные.
public function relations () { return array ( 'R_PriceItems' => array (self: HAS_MANY, WbCatalogPriceItemModel: CLASS, 'category_id'), 'R_CategoryParent' => array (self: BELONGS_TO, WbCatalogCategoryModel: CLASS, array ('parent_id' => 'id'), ) }
public function RecalculatePriceItems () { foreach ($this→R_PriceItems as $price_item) { $price_item→price = $price_item→new_price; } } Как можно заметить в коде выше (метод relations), я определяю классы для связанных моделей динамически, а не текстом. Но это возможно только для PHP > 5.5. Если же (а скорей всего так и есть) сервер не поддерживает такую версию PHP, можно расширить ActiveRecord и вместо CLASS использовать метод _CLASS_(). Потом после перехода на PHP > 5.5 можно будет без проблем заменить _CLASS_() на CLASS простым «Find And Replace».
class ActiveRecord extends CActiveRecord { public static function _CLASS_() { return get_called_class (); } } «ЗА» или «ПРОТИВ» В моём окружении есть сторонники как «ЗА», так и «ПРОТИВ» такого подхода к именованию.В частности, используют же для приватных свойств и методов префикс »_» ($_items, $_version). Нередки случаи, когда для таблиц в БД указывают префикс проекта, например, wb_catalog_item. Исходный код страниц YouTube повсеместно содержит в HTML и CSS префикс «yt-» (это, скорей всего ещё и для того, чтобы при подключении на сторонних сайтах не было конфликтов).
Против такой схемы именования можно привести то, что эта информация является излишней, и (как бы) не стоит мусорить код префиксами и постфиксами. К тому же, необходимо научить других (и новых) сотрудников разбираться, как и что надо именовать (хотя лично я не вижу в этом проблемы).
Да, префиксы и постфиксы несколько замедляют написание кода, но код пишется один раз, а читается и рефакторится далеко не один. Как по мне, так значительно проще читать код, в котором можно сразу определить по префиксам и регистру, где атрибут модели, где метод, а где scope или relation. Префикс «R_» явно даёт понять, что это связь, а постфикс «Model», что это модель. Например, есть класс WebUser — это компонент (extends CWebUser), а есть класс User — и это уже модель.
И напоследок… В Yii повсеместно используются цепочки вызовов. Например, $category→first_item→store. В данном случае, store — это relation, означающий связь со складом. Но в один прекрасный момент необходимо в таблицу catalog_item добавить новый столбец с названием store. Тут и начинается проблема, потому как при обычном подходе без анализа кода нельзя взять и заменить связь store на что-то другое, чтобы не было конфликта имён. В случае же с использованием префиксов всё решится на уровне «Find And Replace» за 1–2–3 минуты.
Мне хочется услышать от аудитории Хабра именно конструктивного обсуждения такого подхода. Возможно, есть иные варианты решения проблем с неуникальными именами.