Тип подсказки - укажите массив объектов
17417 просмотра
5 ответа
Как я могу указать тип аргумента в виде массива? Скажем, у меня есть класс с именем 'Foo':
class Foo {}
а затем у меня есть функция, которая принимает этот тип класса в качестве аргумента:
function getFoo(Foo $f) {}
Когда я передаю массив 'Foo's, я получаю сообщение об ошибке:
Исправляемая фатальная ошибка : аргумент 1, передаваемый getFoo (), должен быть экземпляром Foo, задан массив
Есть ли способ преодолеть эту проблему? может быть что-то вроде
function getFoo(Foo $f[]) {}
Автор: Yoav Kadosh
Источник
Размещён: 12.11.2019 09:39
Ответы (5)
25 плюса
Если вы хотите убедиться, что работаете с «Массивом Foo» и хотите, чтобы методы получали «Массив Foo», вы можете:
class ArrayOfFoo extends \ArrayObject {
public function offsetSet($key, $val) {
if ($val instanceof Foo) {
return parent::offsetSet($key, $val);
}
throw new \InvalidArgumentException('Value must be a Foo');
}
}
тогда:
function workWithFoo(ArrayOfFoo $foos) {
foreach ($foos as $foo) {
// etc.
}
}
$foos = new ArrayOfFoos();
$foos[] = new Foo();
workWithFoo($foos);
Секрет в том, что вы определяете новый «тип» «массива foo», а затем передаете этот «тип», используя защиту хинтинга типов.
Библиотека Haldayne обрабатывает шаблон для проверки требований к членству, если вы не хотите создавать свои собственные:
class ArrayOfFoo extends \Haldayne\Boost\MapOfObjects {
protected function allowed($value) { return $value instanceof Foo; }
}
(Полное раскрытие, я автор Haldayne.)
Историческая справка: Array Of RFC предложил эту функцию еще в 2014 году. RFC был отклонен с 4 годами и 16 годами. Эта концепция недавно появилась в списке внутренних устройств , но жалобы были почти такими же, как и в отношении оригинального RFC: добавление этой проверки значительно повлияло бы на производительность .
Автор: bishop Размещён: 24.12.2013 04:2913 плюса
Старые функции post, но variadic и распаковка массива могут использоваться (с некоторыми ограничениями) для выполнения подсказок по типизированному массиву, по крайней мере с PHP7. (Я не тестировал на более ранних версиях).
Пример:
class Foo {
public function test(){
echo "foo";
}
};
class Bar extends Foo {
//override parent method
public function test(){
echo "bar";
}
}
function test(Foo ...$params){
foreach($params as $param){
$param->test();
}
}
$f = new Foo();
$b = new Bar();
$arrayOfFoo = [$f,$b];
test(...$arrayOfFoo);
//will output "foobar"
Ограничения:
Технически это не решение, так как вы на самом деле не передаете типизированный массив. Вместо этого вы используете оператор распаковки массива 1 («...» в вызове функции), чтобы преобразовать ваш массив в список параметров, каждый из которых должен быть того типа, который указан в объявлении 2 переменной (в котором также используется многоточие).
«...» в вызове функции абсолютно необходимо (что неудивительно, учитывая вышеизложенное). Пытаюсь позвонить
test($arrayOfFoo)
в контексте приведенного выше примера будет получена ошибка типа, так как компилятор ожидает параметр (ы) foo, а не массив. Ниже приведено, хотя и хакерское, решение для прямой передачи массива заданного типа при сохранении некоторой подсказки типов.
Функции Variadic могут иметь только один параметр variadic, и он должен быть последним параметром (иначе как компилятор может определить, где заканчивается параметр variadic и начинается следующий), что означает, что вы не можете объявлять функции в соответствии с
function test(Foo ...$foos, Bar ...$bars){ //... }
или же
function test(Foo ...$foos, Bar $bar){ //... }
Альтернатива «чуть чуть лучше, чем просто проверка каждого элемента»:
Следующая процедура является лучше , чем просто проверкой типа каждого элемента , поскольку (1) она гарантирует параметры , используемые в функциональном теле правильного типа без загромождать функции с проверками типа, и (2) он выбрасывает исключения обычного типа ,
Рассмотреть возможность:
function alt(Array $foos){
return (function(Foo ...$fooParams){
//treat as regular function body
foreach($fooParams as $foo){
$foo->test();
}
})(...$foos);
}
Идея состоит в том, чтобы определить и вернуть результат немедленно вызванного замыкания, которое позаботится обо всем, что связано с вариацией / распаковкой. (Можно расширить принцип далее, определив функцию более высокого порядка, которая генерирует функции этой структуры, сокращая шаблон). В приведенном выше примере:
alt($arrayOfFoo) // also outputs "foobar"
Проблемы с этим подходом включают в себя:
(1) Особенно неопытным разработчикам, это может быть неясно.
(2) Это может привести к снижению производительности.
(3) Он, как и внутренняя проверка элементов массива, рассматривает проверку типов как подробность реализации, поскольку необходимо проверить объявление функции (или использовать исключения типов), чтобы понять, что только конкретно типизированный массив является допустимым параметром. В интерфейсе или абстрактной функции полная подсказка типа не может быть закодирована; все, что можно сделать, это прокомментировать, что ожидается реализация вышеупомянутого вида (или чего-то подобного).
Примечания
[1]. В двух словах: распаковка массива делает эквивалент
example_function($a,$b,$c);
а также
example_function(...[$a,$b,$c]);
[2]. В двух словах: переменные функции формы
function example_function(Foo ...$bar){
//...
}
может быть корректно вызван любым из следующих способов:
example_function();
example_function(new Foo());
example_function(new Foo(), new Foo());
example_function(new Foo(), new Foo(), new Foo());
//and so on
Автор: Evan
Размещён: 28.08.2016 10:38
7 плюса
Извините, PHP не работает таким образом. Это было сделано для быстрого и легкого программирования, и поэтому вас не беспокоит строгая типизация, которая оставляет вас в аду динамического типа без какой-либо помощи (например, компилятор вывода типа). Интерпретатор PHP совершенно не знает, что вы поместили в свой массив, поэтому он должен перебирать все записи массива, если он хочет проверить что-то вроде следующего (что, конечно, не работает в PHP):
function bar(Foo[] $myFoos)
Это сильно влияет на производительность, когда массив становится большим. Я думаю, что именно поэтому PHP не предлагает подсказки для типизированных массивов.
Другие ответы здесь предполагают, что вы создаете свою строго типизированную оболочку массива. Обертки хороши, когда у вас есть компилятор с универсальной типизацией, такой как Java или C #, но я не согласен с PHP. Здесь эти обертки представляют собой утомительный шаблонный код, и вам нужно создать его для каждого типизированного массива. Если вы хотите использовать функции массива из библиотеки, вам нужно расширить свои обертки с помощью функций делегирования с проверкой типов и раздуть свой код. Это может быть сделано в академической выборке, но в производственной системе с множеством классов и коллекций, где время на разработку обходится дорого, а MIPS в веб-кластере мало? Думаю, нет.
Таким образом, просто для проверки правильности типа PHP в сигнатуре функции я бы воздержался от строго типизированных оболочек массивов. Я не верю, что это даст вам достаточно ROI. Поддержка PHPDoc хороших PHP IDE поможет вам больше, и в тегах PHPDoc работает нотация Foo [].
С другой стороны, обертки МОГУТ иметь смысл, если вы можете сосредоточить в них хорошую бизнес-логику.
Возможно, наступит день, когда PHP расширится строго типизированными массивами (или, точнее, строго типизированными словарями). Я хотел бы этого. И с их помощью они могут предоставить подписи подсказки, которые не наказывают вас.
Автор: Rolf Размещён: 30.04.2014 09:393 плюса
function getFoo()
Как правило, у вас будет метод add, который будет вводить подсказку Foo
function addFoo( Foo $f )
Таким образом, метод получения возвращает массив Foo, а метод add может гарантировать, что в массиве есть только Foo.
РЕДАКТИРОВАТЬ Удалил аргумент из геттера. Я не знаю, о чем я думал, тебе не нужен спор в добытчике.
РЕДАКТИРОВАТЬ только для отображения полного примера класса:
class FooBar
{
/**
* @return array
*/
private $foo;
public function getFoo()
{
return $foo;
}
public function setFoo( array $f )
{
$this->foo = $f;
return $this;
}
public function addFoo( Foo $f )
{
$this->foo[] = $f;
return $this;
}
}
Как правило, у вас, и, вероятно, не должно быть, метода setter, поскольку у вас есть метод add, который гарантирует, $foo
что это массив Foo
, но он помогает проиллюстрировать, что происходит в классе.
2 плюса
class Foo {
/**
* @param Foo[] $f
*/
function getFoo($f) {
}
}
Автор: Shami
Размещён: 10.01.2018 02:16
Вопросы из категории :
- php Как вы отлаживаете PHP-скрипты?
- php Заставьте XAMPP / Apache обслуживать файл вне htdocs
- php Как включить файлы PHP, которые требуют абсолютного пути?
- php Скрипт входа со скрытыми кнопками
- php How can I find unused functions in a PHP project
- php Эффективное изменение размера JPEG изображения в PHP
- arrays Как удалить дубликаты из массива C #?
- arrays Как определить размер моего массива в C?
- arrays Каков наилучший способ конвертировать массив в хеш в Ruby
- arrays Сравнение двухбайтовых массивов в .NET
- arrays Можно ли выполнять параллельные обходы в MATLAB так же, как в Python?
- arrays Haxe итерация на динамическом
- type-hinting Как решить "должен быть экземпляр строки, заданной строки" до PHP 7?
- type-hinting Clojure defmacro теряет метаданные
- type-hinting Невозможно передать нулевой аргумент при использовании подсказки типа
- type-hinting Поддерживает ли Ruby хинтинг типов?
- type-hinting Подсказка типа собственности Netbeans
- type-hinting Как выполнить модульное тестирование функций, использующих подсказки типов