Восемь причин изучить PHPDoc
Часто встречаю вопрос о том, что же это за странные блоки комментариев постоянно генерируются в представлениях:
<?php /* @var $this yii\web\View */ /* @var $searchModel \app\models\search\UserSearch */ /* @var $dataProvider yii\data\ActiveDataProvider */
в ActiveRecord-классах:
/** * This is the model class for table "{{%user}}". * * @property integer $id * @property string $username * @property string $auth_key * @property string $password_hash * @property string $email */ class User extends ActiveRecord { ... }
и перед всеми методами:
/** * Saves the current record. * @param boolean $runValidation whether to perform validation before saving the record. * @param array $attributeNames list of attribute names that need to be saved. * @return boolean whether the saving succeeded (i.e. no validation errors occurred). */ public function save($runValidation = true, $attributeNames = null) { ... }
Что они обозначают и зачем они нужны? Это какой-то особый синтаксис объявления переменных в PHP или что?
Нет, это не совсем синтаксис PHP. А точнее, к самому PHP он никакого отношения не имеет и сам PHP интерпретатор его никогда не парсит. Это PHPDoc-блок, зародившийся ещё как JavaDoc и перешедший в PHPDocumentor
Пока мы не кодим так, как зажигают эти джентльмены:
но попробуем разобраться.
Все эти вещи, судя по названию, как-то связаны с документацией. С неё и начнём.
Документация кода
Кому то стало лень писать документацию отдельно и он, вероятно, решил: «Отдельно документировать проект сложно и муторно. Нам же проще описывать прямо в комментариях каждый метод и класс. Давайте сделаем особый вид комментариев и при необходимости будем генерировать документацию по нему». И понеслось. В итоге придумали конструкции для объявления переменных, их типов и прочей метаинформации. И написали автоматический генератор, который парсит файлы в папке и генерирует HTML-файлы для каждого нашего класса.
Если посмотреть в API Reference и в код класса то увидим одно и то же:

namespace yii\db; /** * ActiveRecord is the base class for classes representing relational data in terms of objects. * * ... * * As an example, say that the `Customer` ActiveRecord class is associated with the `customer` table. * This would mean that the class's `name` attribute is automatically mapped to the `name` column in `customer` table. * Thanks to Active Record, assuming the variable `$customer` is an object of type `Customer`, to get the value of * the `name` column for the table row, you can use the expression `$customer->name`. * In this example, Active Record is providing an object-oriented interface for accessing data stored in the database. * But Active Record provides much more functionality than this. * * To declare an ActiveRecord class you need to extend [[\yii\db\ActiveRecord]] and * implement the `tableName` method: * * ```php * <?php * * class Customer extends \yii\db\ActiveRecord * { * public static function tableName() * { * return 'customer'; * } * } * ``` * ... */ class ActiveRecord extends BaseActiveRecord { ... }
Теперь понятно, как этот сайт так быстро меняется при каждом обновлении исходников. Оказывается, что он составлен не вручную, а автоматически сгенерирован по коду фреймворка.
Так что можем уже сформулировать первый бонус, который нам дают PHPDoc-блоки:
Применение первое: Возможность одной командой в консоли сгенерировать документацию с описанием всех классов, полей и методов своего проекта.
Но кроме этого чем он полезен в реальной жизни? Рассмотрим ещё несколько применений.
Виртуальные поля
В модели данных он пригодится для той же автогенерации полей по классу, но для чего его используют в представлениях, которые в документации не выводятся?
Оказалось, что формат PHPDoc оказался настолько удачным, что его встроенную поддержку наряду с JavaDoc подхватили практически все IDE вроде PhpStorm, NetBeans и прочие. В PHP нет встроенной типизации для чисел и строк, поэтому указывать тип в комментарии (чтобы не забыть) было бы полезно. Вот и нашему PHP-редактору оттуда тоже оказалось удобно парсить переменные и их типы.
Например, был класс без полей:
class Post extends ActiveRecord { public static function tableName() { return '{{%post}}'; } }
и непонятно что там, так как Yii2 берёт атрибуты из таблицы в базе данных. Автоподстановка видит только поля и методы из базового класса ActiveRecord:

А наши поля подчёркивает, при этом ругаясь, что их в объекте нет:

Можно заморочиться и написать плагин, который бы парсил поля из базы для каждой таблицы. Но это явно не лёгкий путь.
А давайте просто обозначим поля в PHPDoc-блоке (комментарии особой формы):
/** * @property integer $id * @property integer $user_id * @property integer $category_id * @property integer $created_at * @property integer $updated_at * @property string $title * @property string $content * @property integer $status */ class Post extends ActiveRecord { public static function tableName() { return '{{%post}}'; } }
и редактору сразу станет понятно, какие поля теперь там есть для автоподстановки и какого они типа:

Теперь он в курсе наших дел и больше не ругается.
Или если в классе есть связи:
/** * @property integer $id * @property integer $user_id * @property integer $category_id * @property string $title * @property string $content */ class Post extends ActiveRecord { public function getCategory() { return $this->hasOne(Category::className(), ['id' => 'category_id']); } public function getUser() { return $this->hasOne(Category::className(), ['id' => 'category_id']); } public function getTags() { return $this->hasMany(Tag::className(), ['id' => 'tag_id'])->viaTable(PostTag::tableName(), ['post_id' => 'id']); } }
В коде мы можем использовать их просто как поля category, user и tags:
echo $post->category->name; echo $post->user->username; foreach ($post->tags as $tag) { echo $tag->name; }
Но этих полей в классе нет. Всё работает через виртуальные методы и геттеры. Поэтому нам ничего не остаётся, как указать эти псевдополя и их типы явно:
/** * @property integer $id * @property integer $user_id * @property integer $category_id * @property string $title * @property string $content * @property User $user * @property Category $category * @property Tag[] $tags */ class Post extends ActiveRecord { ... }
Так что PHPDoc-блок перед классом может содержать полное перечисление того, чего в классе нет.
Применение второе: Указание псевдополей класса.
В примерах мы рассмотрели пока только поля. К псевдометодам подойдём позже.
Типы существующих полей
Помимо блока перед классом можно использовать и другие места.
Допустим, что у нас есть приватное поле _user у класса PasswordChangeForm:
class PasswordChangeForm extends Model { ... private $_user; public function __construct($user, $config = []) { $this->_user = $user; parent::__construct($config); } ... public function changePassword() { if ($this->validate()) { $user = $this->_user; $user->setPassword($this->newPassword); return $user->save(); } else { return false; } } }
Но на строках:
$user = $this->_user; $user->setPassword($this->newPassword); return $user->save();
редактор впадает в ступор и методы setPassword и save подсвечивает жёлтым, мотивируя это тем, что таких методов в этой переменной нет:

А если мы подскажем, что там у нас находится объект класса User:
class PasswordChangeForm extends Model { /** * @var User */ private $_user; }
то всё заработает как нам этого и хотелось.
Здесь мы аннотации @var передаём только тип. Но вообще ей можно передавать имя переменной, её тип или оба аргумента сразу.
Применение третье: Подсказка типов для имеющихся полей в классе.
Тип возвращаемого результата
Аналогично, если мы аннотацией @return укажем тип возвращаемого методом объекта:
class UsersController extends Controller { /** * @param integer $id * @return User * @throws NotFoundHttpException */ protected function findModel($id) { if (($model = User::findOne($id)) !== null) { return $model; } else { throw new NotFoundHttpException('The requested page does not exist.'); } } }
то при использовании этого метода наша система разработки поймёт, что внутри переменной $user после вызова данного метода окажется объект класса User:
class UsersController extends Controller { public function actionUpdate($id) { $model = $this->findModel($id); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { return $this->render('update', [ 'model' => $model, ]); } } }
и больше не будет ругаться на ранее неизвестные ей методы load и save.
А что если какой-либо метод возвращает нам либо User, либо null? Тогда можно перечислить варианты через вертикальную черту:
/** * @param integer $id * @return User|null */
И IDE будет учитывать оба случая.
Применение четвёртое: Подсказка типов аргументов и типа возвращаемого результата (при наличии) у процедур, функций, методов.
Переменные из ниоткуда
Или ещё вариант. Есть некое представление, в которое из контроллера передаётся переменная $model. К тому же, это представление рендерится в объекте класса \yii\web\View, который и будет доступен через $this:
<?php use yii\helpers\Html; use yii\widgets\DetailView; $this->title = $model->meta_title; $this->registerMetaTag(['name' => 'description', 'content' => $model->meta_description]); $this->registerMetaTag(['name' => 'keywords', 'content' => $model->meta_keywords]); $this->params['breadcrumbs'][] = ['label' => 'Блог', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; <div class="user-view"> <h1> Html::encode($this->title) </h1> ... </div>
Но IDE не в курсе наших планов, поэтому сразу подсвечивает переменные $this и $model как не определённые в этом файле. Для исправления ситуации мы можем добавить сколько угодно Doc-блоков с аннотацией @var прямо внутрь кода представления:
<?php use yii\helpers\Html; use yii\widgets\DetailView; /** @var $this \yii\web\View */ /** @var $model \app\models\User */ $this->title = $model->meta_title; ...
При этом для @var можно указать сначала тип, потом имя переменной:
/** @var \app\models\User $model */
В итоге автоподстановка, поиск и автозамена полей и методов объектов заработают для этих переменных автоматически.
Применение пятое: Обозначение переменных, каким-либо образом переданных извне.
Подмена типа
Не всегда мы в контроллерах и прочих компонентах используем метод findModel. Часто можно напрямую в коде выполнить какой-нибудь запрос:
$model = Post::find()->where(['id' => $id])->andWhere(...)->one(); echo $model->title;
В итоге IDE по цепочке наследования подсмотрит аннотации метода ActiveRecord::find:
class ActiveRecord extends BaseActiveRecord { /** * @inheritdoc * @return ActiveQuery the newly created [[ActiveQuery]] instance. */ public static function find() { return Yii::createObject(ActiveQuery::className(), [get_called_class()]); }
и, так как указана аннотация @inheritdoc, пойдёт ещё выше в аннотации этого же метода в интерфейсе:
interface ActiveRecordInterface { /** * Creates an ActiveQueryInterface instance for query purpose. * ... * @return ActiveQueryInterface the newly created [[ActiveQueryInterface]] instance. */ public static function find(); }
и склеит всё воедино.
В итоге IDE по строке:
/** * @return ActiveQuery */
поймёт, что из метода find должен вернуться экземпляр класса \yii\db\ActiveQuery и методы where и one будут вызываться уже у него:
class ActiveQuery extends Query implements ActiveQueryInterface { ... /** * Executes query and returns a single row of result. * @param Connection $db the DB connection used to create the DB command. * @return ActiveRecord|array|null a single row of query result. */ public function one($db = null) { ... } }
и здесь мы видим, что метод one возвращает либо экземпляр ActiveRecord, либо массив (если вызывали asArray()), либо null. Редактор так и будет думать, поэтому выдаст замечание при попытке обратиться к полю title:
$model = Post::find()->where(['id' => $id])->one(); echo $model->title;
Для правильной работы нам нужно явно указать тип переменной с помощью Doc-блока перед присваиванием:
/** @var \app\models\Post $model */ $model = Post::find()->where(['id' => $id])->one(); echo $model->title;
или непосредственно перед использованием объекта:
$model = Post::find()->where(['id' => $id])->one(); /** @var \app\models\Post $model */ echo $model->title;
Это удобно делать в циклах по различным выборкам:
foreach (Category::find()->orderBy('name')->each() as $category) { /** @var \app\models\Category $category */ echo $category->title; }
Применение шестое: Подмена типа уже существующих переменных.
И вернёмся к методам.
Подключение примесей
Вначале мы рассмотрели виртуальные переменные. Теперь предположим, что к своему классу мы примешиваем любое поведение вроде:
composer require yii-dream-team/yii2-upload-behavior
Его достаточно добавить в метод behaviors:
/** * @property integer $id * @property integer $user_id * @property integer $category_id * @property string $title * @property string $content * @property string $image */ class Post extends ActiveRecord { ... public function behaviors() { return [ [ 'class' => ImageUploadBehavior::className(), 'createThumbsOnRequest' => true, 'attribute' => 'image', 'filePath' => '@webroot/uploads/posts/[[pk]].[[extension]]', 'fileUrl' => '@web/uploads/posts/[[pk]].[[extension]]', 'thumbPath' => '@webroot/uploads/posts/[[profile]]_[[pk]].[[extension]]', 'thumbUrl' => '@web/uploads/posts/[[profile]]_[[pk]].[[extension]]', 'thumbs' => [ 'thumb' => ['width' => 100, 'height' => 100], 'preview' => ['width' => 250, 'height' => 180], ], ], ]; } }
и в представлениях выводить оригинал или превью:
<?= Html::img($post->getImageFileUrl('image')) Html::img($post->getThumbFileUrl('image', 'preview'))
А мы помним, что IDE ругается на всё, чего нет в классе. Но с помощью аннотации @mixin, которую поддерживает IDE PhpStorm и, возможно, некоторые другие, можно «подмешать» класс поведения:
/** * @property integer $id * @property integer $user_id * @property integer $category_id * @property string $title * @property string $content * @property string $image * * @mixin ImageUploadBehavior */ class Post extends ActiveRecord { ... }
и все методы getImageFileUrl и прочие будут доступны в автоподстановке.
Но есть один нюанс. Помимо нужных методов в классе поведения имеется и много ненужных. Например, вспомогательные resolveProfilePath или createThumbs, которые мы использовать не будем.
В таком случае вместо примешавания всего класса поведения с помощью @mixin мы можем просто добавить определение только пары нужных нам виртуальных методов:
/** * @property integer $id * @property integer $user_id * @property integer $category_id * @property string $title * @property string $content * @property string $image * * @method getImageFileUrl($attribute, $emptyUrl = null) * @method getThumbFileUrl($attribute, $profile = 'thumb', $emptyUrl = null) */ class Post extends ActiveRecord { ... }
Аналогично можно добавлять сигнатуры любых своих методов, работающих через свой магический метод __call.
Применение седьмое: Определение псевдометодов класса.
Программирование с аннотациями
Помимо простой работы с PHPDocumentor некоторые системы пошли дальше и придумали для своих целей собственные виды аннотаций. И некий программный код через рефлексию парсит эти данные. Взять хоть первый попавшийся пример с сайта StackOverflow:
$r = new ReflectionClass($class); $doc = $r->getDocComment(); preg_match_all('#@(.*?)\n#s', $doc, $annotations); print_r($annotations[1]);
Аналогично можно получить $r->getMethods() и парсить уже их.
В итоге этот подход нашёл новое применение. Например, в Symfony Framework с помощью собственных аннотаций (помимо конфигурации в YAML или XML-файлах) с использованием пакета doctrine/annotations можно конфигурировать те же сущности прямо в коде:
namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="product") */ class Product { /** * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(type="string", length=100) */ protected $name; /** * @ORM\Column(type="decimal", scale=2) */ protected $price; /** * @ORM\Column(type="text") */ protected $description; }
или ту же маршрутизацию контроллеров:
class BlogController extends Controller { /** * @Route("/blog/{slug}", name="blog_show") */ public function showAction($slug) { // ... } }
И фреймворк легко парсит эти данные и кеширует в простые PHP-массивы, чтобы не парсить их каждый раз снова и снова.
Также в уроке по тестированию мы рассматривали аннотации вроде @group и @dataProvider для тестов в пакете PHPUnit.
Этот подход уже мало связан с оригинальным PHPDoc, так как просто использует его идею. Но при этом друг другу никто не мешает и можно спокойно использовать различные ключи вместе:
class Product { /** * @var string * @ORM\Column(type="string", length=100) */ protected $name; }
Многим такой подход с конфигурированием аннотациями в Symfony не нравится, так как он нарушает принцип единой ответственности, смешивая программный код и конфигурацию в одном файле. Так что используйте по своему усмотрению.
Восьмая причина: Появление программных систем с поддержкой специфических аннотаций.
Пока на этом всё. Если в комментариях приведут и другие примеры использования, то дополню статью.
И в итоге
С помощью PHPDoc-блоков можно легко «научить» свой редактор понимать вас с полуслова и всегда знать, какие переменные и каких типов используются в каждой строчке кода.
После этого не будет проблем с автоподстановкой, опечатками, несовпадениями типа, неопределёнными переменными, с автоматическим переименованием полей или методов любого класса и прочим автоматическим рефакторингом.
Дружите со своей IDE и она облегчит вашу жизнь.
Ну и, вроде, праздник скоро, так что не спалите ёлку:
АртёмЗдравствуйте!
Подскажите, пожалуйста, где описывать собственные компоненты, чтобы PhpStorm не подчёркивал их при вызове Yii::$app->myComponent->myMethod
Спасибо.
Дмитрий ЕлисеевВ простейшем случае можно получить компонент явно:
/** @var \app\components\MyComponent $component */ $component = Yii::$app->get('myComponent'); $component->myMethod();
АртёмЭто понятно, но это не удобно.
Дмитрий ЕлисеевТогда придумайте другой способ.
Андрей – lookatme.pwДля этого в нашем проекте мы создали файлик codeAssist.php следующего содержания:
/** * Класс приложения для работы подсказок IDE * * @property \common\components\ShopSetting $shopSettings Компонент настроек для магазина. Свойство только для чтения * @property \common\components\Setting $settings Компонент настроек платформы. Свойство только для чтения */ abstract class CodeAssistApplication extends Application { } /** * Вспомогательный класс для работы подсказок IDE * */ class Yii extends BaseYii { /** * @var \yii\console\Application|\yii\web\Application|CodeAssistApplication the application instance */ public static $app; }
Roman Dukuyкак использовать ваш файл?
Андрей – lookatme.pwПросто положить в папку с проектом. У нас он лежит здесь:
backend/runtime/codeAssist.php
Дмитрий ЕлисеевА как борться теперь с конфликтом вроде multiple definition for class?
Андрей – lookatme.pwНу, если речь о phpStorm'е идет, то кликаем правой кнопкой по vendor/yiisoft/yii2/Yii.php и выбираем в меню "Mark as Plain Text"
Roman DukuyДа, но после пересборки vendor все заново делать
MaxxiДля этого можно унаследовать свой Application, в котором в виде хинтов @property указать свои компоненты. Не знаю, на сколько это целесообразно, но есть такой рецепт. :)
Раструсный Владислав – www.fractalizer.ruПочитайте документацию по расширенным метаданным в PHPStorm: https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata
Возможно, там найдется что-нибудь интересное.
РомаБыло бы ещё полезно узнать как автоматически генерировать API documents с возможностью пробовать в работе методы
НикитаА вот как scopes прокомментировать, что бы ide потом подставила ключи массивов, как функцию или так не реально сделать?
НикитаЗабыл добавить что речь идет про Yii1)
НикитаА вот как scopes прокомментировать, что бы ide потом подставила ключи массивов, как функцию или так не реально сделать?
Дмитрий ЕлисеевТакже через @method у класса модели.
НикитаА все понял спасибо)
slo_nikИнтересно.
Но я пользуюсь sublime text 3, есть для этого редактора такая возможность?
Arthur MrЧто мешает проверить?
Arthur MrСпасибо за статью, как всегда замечательно! "@mixin" я как-то пропустил, теперь буду использовать)
Заметил небольшие опечатки в нескольких местах: в комментарии "$post", а в коде "$model".
Roman DukuyА что сделать чтоб не было подсветки серым "Field accessed via magic methot"
Yii::$app->conf->
Дмитрий ЕлисеевВ первом комментарии уже, вроде, ответили.
ИванА как можно описать анонимную функцию, интересует конкретно конструкция use, например:
/** * @param $model Devices * @return string */ function ($model) use ($target_id, $dev_id, $id_def){ return Html::a('<span class="glyphicon glyphicon-ok"></span>', ['dt-enquiry-devices/create', 'id' => $model->id, 'id_doc' => $target_id, 'dev_id' => $dev_id, 'id_def' => $id_def]); }
Дмитрий Елисеев/** * @param $model Devices * @return string */ function (Devices $model) use ($target_id, $dev_id, $id_def) { /** @var integer $target_id */ return ...; }
Андрей РешетченкоВ нетбинсе такие конструкции, как указание типа локальной переменной (/** @var \app\models\Category $category */) или указания массивов в ява-стиле (@property Tag[] $tags) не работают. Да и в документации такое не описано. Так что это кастомные плюшки пхпшторма.
alexanderОбратил внимание, что "@mixin MyBehavior" не наследует свойства вроде "@property MyModel[] $myModel" прописанные прямо перед классом в поведении, при этом реальные методы поведения ide видит, это нормально и надо прописать такие свойства прямо в owner или есть решение без дублирования кода?
Дмитрий ЕлисеевТогда пропишите явно.
ДенисПодскажите, а как прописывать, например в том же slimphp есть такие конструкции $container['request']->getUri() и этот метод не видит шторм.. а сама переменная $container указана, как интерфейс ContainerInterface и все ок.. Спасибо!
Дмитрий Елисеев
ИльяВот прям сердечное спасибо за статью - вроде ничего особенного, а в разработке приложения очень помогает (пользуюсь PHPStorm)!!!
Vlad/** @var \app\models\Post $model */
echo $model->title;
вот этот случай можно как-то обрулить через описание единоразово в моделе(возможно через переопределение чего-то). но я забыл как и нигде не могу найти( но я точно видел довольно простое решение, чтобы не писать это каждый раз.
ОлегДмитрий, спасибо за столь подробную статью!
А можно ли как-нибудь добиться автоподстановок для полей объекта прямо внутри кода, а не при объявлении класса?
Например, мне известно, что в массиве $array имеется 3 элемента, которые я хочу сделать полями объекта:
Как прописать эти конкретные поля в аннотациях, чтобы IDE их предлагала для автоподстановки?
Дмитрий ЕлисеевВроде никак.
Denis KДобрый день.
У меня вот такой вопрос - на днях зашел разговор на работе о том на сколько уместно использовать сейчас phpdoc
Есть мнение, что это уже не настолько необходимо, т.к. IDE умеют читать и подставлять описание на основе типов входных параметров.
И что код должен быть гворящим сам за себя, т.е. он должен быть написан так, что не потребуется делать дополнительные комментарии и поэтому phpdoc пережиток прошлого.
Если кто - то пишет phpdoc, то это говорит о том, что это плохой программист.
В своих новых уроках, Вы не используете phpdoc, но это скорее в угоду скорости разработки.
Каких то холиваров по этому поводу я нигде в интернете не видел, в общем интересно Ваше мнение.
Дмитрий ЕлисеевВ PHP 7 появилась возможность указания скалярных типов аргументов, а сейчас в 7.4 и описание типов полей, поэтому простые блоки:
уже не нужны, так как это уже описывается непосредственно типами:
Сейчас PHPDoc остаётся нужен только для особых ситуаций вроде этой:
Здесь мы указываем, что это array именно из постов Post[] и что этот метод кидает исключение DomainException.
В языке Java это всё указывается типами:
а в PHP такого ещё нет.
Denis KА вот какие - то стандарты есть, которые предписывают использовать\не использовать комментарии?
Я ничего подобного не видел и получается, что данная практика уже больше на совести или желании команды?
К чему этот вопрос?
К тому, что если команда привыкла писать такие комментарии, то отучить ее уже будет сложно и в любом случае надо как -то аргументировтаь свое предложение.
Вот стандарт или какие то соглашения по типу PSR как раз в тему.
Дмитрий ЕлисеевЗа типами следят статические анализаторы кода.
DimaКак же мы жили раньше без этого?) На сегодня необходимо знать такое кол-во технологий, подходов, парадигм, языков..., каждая из которых обновляется раз в пару месяцев что просто физически невозможно следовать всем этим стандартам. Вникайте в это Doc только если вам заплатят деньги на фирме за это, или самому интересно. Я конечно не работал в гугле, но в тех компаниях где был, об этом даже не говорили (хотя в одной мы написали собственный фреймворк, который и кормит нас всех). Я вообще считаю что на документацию надо выделять отдельного человека, или доплачивать.
Виктор КуровскийКомментирование в стиле PhpDoc - это очень удобно и помогает в больших проектах, особенно если используете IDE (например PhpStorm), который поддерживает это.
Я одно время программировал в Notepad++ и считал, что всякие там IDE вовсе не нужны и без них справляюсь, достаточно подсветки синтаксиса. Я так думал именно потому, что не работал с IDE. Когда начал осваивать и переходить PhpStorm, понял всю реальную прелесть в автоподстановке и подсказках. Когда обычным кликом по методу тебя перекидывает в файл и класс, который содержит этот метод. До этого мне приходилось искать этот файл, открывать, далее искать этот метод - сколько же лишних действий это создаёт, отвлекает от текущего файла. Также наведение мыши на метод - отображает подсказку, описание метода из PhpDoc, в скобочках отображает название параметров и их типы.
В MVC модели разделения данных во вьюшках, особенно когда их несколько и одна в другой подключается, теряется связь между переменными. Они переименовываются и не понятно какая что означает. Когда вверху файла объявишь через /** @var */ тип либо какую-то подсказку даёшь, как эта переменная формировалась, сразу же становится всё понятно и не надо возвращать своё внимание к самым истокам формирования и передачи переменной, чтобы найти все её концы во вьюшках.
Преимущество просто очевидное. Предполагаю, что вы не работает в IDE (PhpStorm либо ему подобных), иначе данного вопроса скорее всего просто бы не возникло.
СаняТо yii, то ларавель,... документация еще существует для тестов. самое важное и не упомянули.
Дмитрий ЕлисеевА какое отношение документация имеет к тестам?
АндрейДмитрий подскажите пожалуйста, в репозиториях хочется использовать код таким образом
public function find($id): ?Category { return Category::find()->andWhere(['id' => $id])->one(); }Но при этом phpStorm выделяет этот код другим цветом, мол там есть несоответствие типов. Отображает такой нотис
Можно ли это как-то пофиксить?
АндрейЕсли я правильно понял, то всё это теперь решается неймспейсами и указанием типов для переменных. Да?
Дмитрий ЕлисеевДя, с PHP 8 теперь можно указывать типы и для полей. А PHPDoc можно оставить только для нестандартных типов вроде `Post[]` для массивов.