PhpStorm выводит «смешанный» тип в моих типизированных свойствах

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

Свойства типизированы, что означает, что PHP выдаст ошибку TypeError, если будет передано что-либо, кроме указанного типа.

Однако PhpStorm, похоже, распространяет тип mixed из доступа к массиву в свойство класса.

Я изо всех сил пытаюсь объяснить это словами, поэтому вот пример сценария:

<?php

class TestClass
{
    public readonly string $myString;
    public readonly int $myInt;
    public readonly array $myArray;

    public function __construct(array $src)
    {
        $this->myString = $src['stringVal'];
        $this->myInt = $src['intVal'];
        $this->myArray = $src['array'];
    }
}

$arr = [
    'stringVal' => 123,
    'intVal' => "I am a string",
    'array' => null,
];

$x = new TestClass($arr); // throws TypeError from within the constructor

$y = new TestClass($x->myInt); // PhpStorm doesn't see anything wrong with this???

Вы можете видеть, что есть типы для всех трех свойств. Вы можете посмотреть на сценарий и увидеть, что он потерпит неудачу. Сценарий в том виде, в котором он написан, выдает ошибку TypeError точно так, как вы ожидаете, когда пытается установить $this->myString.

Однако, если я наведу курсор на любое из свойств класса, PhpStorm добавит к свойству тип mixed:

Поскольку PhpStorm обрабатывает все свойства как «x или смешанные», он не видит ничего плохого в явно некорректной последней строке скрипта, где мы пытаемся передать int в конструктор, для которого требуется массив:

Как я могу заставить PhpStorm прекратить вывод mixed этих свойств?

Обновление: это не только mixed исходит из массива, кажется, что PhpStorm просто предполагает, что все, что происходит в конструкторе, является допустимым, независимо от типов свойств (?)

Другой пример:

class TestClass2
{
    public readonly int $myInt;

    public function __construct()
    {
        $this->myInt = "hello world";
    }
}

Конструктор снова выдает ошибку TypeError, как и следовало ожидать. Но PhpStorm, кажется, согласен предположить, что свойство будет принимать строку:

Вы можете помочь подсказке типов PHPStorm следующим образом: $this->myInt = (int)$src['intVal']; принудительное приведение типов. Лично я считаю, что принудительное приведение очень хорошо подходит для обеспечения того, чтобы 0 распознавалось как 0, даже если оно ошибочно сохранено как '0' и т. д.

Martin 10.04.2023 15:24

Не объясняет поведение PhpStorm, о котором вы должны сообщить JetBrains в отчете об ошибке, но вы можете сделать что-то очень похожее и без отображения: класс, подобный приведенному выше коду, скрывает важные детали и не должен беспокоить класс, чтобы взять на себя это.

Jared Farrish 10.04.2023 15:28

Вы можете отправить отчет об ошибке PHPStorm здесь

Martin 10.04.2023 15:31

@Martin Я проделывал этот трюк в некоторых местах, но я не думаю, что собираюсь изменить привычки всех остальных, чтобы обойти (очевидную) проблему с ошибкой / конфигурацией в моей среде IDE :)

maples 10.04.2023 15:34

@JaredFarrish Я не знал об этом синтаксисе инициализации, он выглядит очень полезным!

maples 10.04.2023 15:35

Я немного сомневаюсь, что вещи слишком милые. Например, в этом примере свойства (которые являются общедоступными) сопоставляются напрямую, без посредничества. Когда в него войдет массив? Возможно, хранится в контексте чего-то другого. В конечном итоге вам может быть трудно изменить эти свойства, если то, что инициализирует объект, хранится в состоянии и его нелегко или практически увидеть/изменить (особенно с помощью инструментов рефакторинга). Если вы собираетесь использовать массивы таким образом, я бы предложил создать статические методы with<>(), которые отображают этот массив для вас, и дать им соответствующие имена.

Jared Farrish 10.04.2023 15:44

Пример использования инициализатора with: 3v4l.org/mUqSd#v8.1.17

Jared Farrish 10.04.2023 15:46

@JaredFarrish Это, по общему признанию, надуманный пример, иллюстрирующий проблему IDE, которую я пытаюсь решить - я бы не рекомендовал писать такой класс обычно :) Реальные сценарии, с которыми я работаю, немного сложнее их, но сводится к тому, что «среда IDE делает что-то неправильно, когда я назначаю что-то неправильное/подозрительное в конструкторе».

maples 10.04.2023 15:49

Верно, и об этом следует сообщить JetBrains.

Jared Farrish 10.04.2023 15:50

Попался. Я надеялся, что там будет какая-то настройка или что-то, чего мне не хватало, но я отправлю отчет об ошибке.

maples 10.04.2023 16:37
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
10
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я подал отчет об ошибке в JetBrains, и они дали мне следующий обходной путь:

В качестве обходного пути вы можете либо пометить файл declare(strict_types=1);, либо включить PHP | Совместимость типов | Нарушение правил строгой проверки типов: Включить для всех файлов.

В моем случае настройка проверки кода была наиболее подходящей и решила проблему для меня.

Другие вопросы по теме