Префиксы и постфиксы в PHP (и CSS)

в 13:39, , рубрики: css, IT-стандарты, php, yii, БЭМ, префиксы, метки: , , , ,

Префиксы и постфиксы в 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 минуты.


Мне хочется услышать от аудитории Хабра именно конструктивного обсуждения такого подхода. Возможно, есть иные варианты решения проблем с неуникальными именами.

Автор: zalatov_a

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js