Как решить, что должен быть экземпляр строки, строка, заданная до PHP 7?

Вот мой код:

function phpwtf(string $s) {
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

Что приводит к этой ошибке:

Уловимая фатальная ошибка: аргумент 1, переданный в phpwtf (), должен быть экземпляром строки, заданной строкой

Это больше, чем немного оруэлловское, видеть, как PHP распознает и отклоняет желаемый тип на одном дыхании. Черт побери, пять огней.

Что эквивалентно подсказке типов для строк в PHP? Дополнительное внимание к ответу, который точно объясняет, что здесь происходит.


person leepowers    schedule 05.11.2010    source источник
comment
Ну, это потому, что вы делаете это неправильно. Ваш код изначально не должен работать. Прочтите о манипуляциях с типами в документации по PHP. PHP имеет динамическую типизацию и слабую типизацию. Вы можете использовать (string) для приведения аргумента к строке (хотя только в теле функции), но вы можете только намекать на объекты и массивы, как вы это делаете в своем фрагменте кода.   -  person Richard Knop    schedule 05.11.2010
comment
Проблема в том, что вы допустили небольшую ошибку. Есть четыре огонька!   -  person CJ Dennis    schedule 12.02.2014
comment
@Gordon, тестировал на 5.6. По-прежнему не повезло.   -  person Pacerier    schedule 03.04.2015
comment
@Pacerier Следите за последними событиями на странице wiki.php.net/rfc.   -  person Gordon    schedule 04.04.2015
comment
По-видимому, скалярное указание типов (поскольку OP интуитивно ожидалось, что это нечто выше) наконец было одобрено в соответствии с RFC для PHP * 7 * согласно source. Утвержденный RFC, по-видимому, также предоставляет синтаксический сахар для проверки типов возвращаемых значений а также параметры (аргументы). Это было давно.   -  person Seldom 'Where's Monica' Needy    schedule 28.10.2015


Ответы (9)


До PHP 7 указание типов можно было использовать только для принудительного выбора типов объектов и массивов. Скалярные типы не имеют подсказок по типу. В этом случае ожидается объект класса string, но вы даете ему (скаляр) string. Сообщение об ошибке может быть забавным, но с самого начала оно не должно работать. Учитывая систему динамической типизации, это действительно имеет какой-то извращенный смысл.

Вы можете только вручную "ввести подсказку" скалярных типов:

function foo($string) {
    if (!is_string($string)) {
        trigger_error('No, you fool!');
        return;
    }
    ...
}
person deceze♦    schedule 05.11.2010
comment
@deceze, есть ли синтаксис для хинтинга обратного типа? Например. что угодно кроме массивов. - person Pacerier; 03.04.2015
comment
@Pacerier Нет, нет. - person deceze♦; 04.04.2015
comment
Этот ответ недействителен для PHP 7 - person Jose Nobile; 06.12.2015

Из руководства по PHP:

Подсказки типов могут быть только объектами и массивами (начиная с PHP 5.1). Подсказки традиционных типов с int и string не поддерживаются.

Итак, оно у вас есть. Сообщение об ошибке не очень полезно, но я вам это даю.

** 2017 Редактировать **

PHP7 представил больше объявлений типов данных функций, и вышеупомянутая ссылка была перемещена на Аргументы функции: объявления типов. С этой страницы:

Допустимые типы

  • Имя класса / интерфейса: параметр должен быть экземпляром данного класса или интерфейса. (начиная с PHP 5.0.0)
  • self: параметр должен быть экземпляром того же класса, для которого определен метод. Это можно использовать только в методах класса и экземпляра. (начиная с PHP 5.0.0)
  • массив: параметр должен быть массивом. (начиная с PHP 5.1.0)
  • callable: параметр должен быть допустимым вызываемым. (начиная с PHP 5.4.0)
  • bool: параметр должен быть логическим значением. (начиная с PHP 7.0.0)
  • float: параметр должен быть числом с плавающей запятой. (начиная с PHP 7.0.0)
  • int: параметр должен быть целым числом. (начиная с PHP 7.0.0)
  • строка: параметр должен быть строкой. (начиная с PHP 7.0.0)
  • iterable: параметр должен быть либо массивом, либо экземпляром Traversable. (начиная с PHP 7.1.0)

Предупреждение

Псевдонимы для указанных выше скалярных типов не поддерживаются. Вместо этого они рассматриваются как имена классов или интерфейсов. Например, для использования логического значения в качестве параметра или типа возвращаемого значения потребуется аргумент или возвращаемое значение, которое является экземпляром логического класса или интерфейса, а не типа bool:

<?php
  function test(boolean $param) {}
  test(true);
?>

Приведенный выше пример выведет:

 Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1

Последнее предупреждение действительно важно для понимания ошибки. Аргумент должен иметь тип строка, заданная строка; поскольку в качестве типа аргумента разрешены в основном только имена классов / интерфейсов, PHP пытается найти строку имени класса, но не может найти ее, потому что это примитивный тип, поэтому возникает эта неудобная ошибка.

person Yanick Rochon    schedule 05.11.2010

PHP позволяет «намекать», когда вы предоставляете класс для указания объекта. Согласно руководству по PHP, «Типовые подсказки могут быть только объектами и массивами (начиная с PHP 5.1). Традиционные типы подсказок с int и string не поддерживаются». Ошибка сбивает с толку из-за того, что вы выбрали «строку» - поместите «myClass» на ее место, и ошибка будет читаться по-другому: «Аргумент 1, переданный в phpwtf (), должен быть экземпляром myClass, указанная строка»

person Surreal Dreams    schedule 05.11.2010

Как уже говорили другие, подсказка типов в настоящее время работает только для типов объектов. Но я думаю, что вызванная вами конкретная ошибка может быть связана с подготовкой к предстоящему строковому типу SplString < / а>.

Теоретически он ведет себя как строка, но поскольку это объект, он прошел бы проверку типа объекта. К сожалению, этого еще нет в PHP 5.3, может быть и в 5.4, поэтому не тестировал.

person mario    schedule 05.11.2010

В PHP 7.0 объявления типов допускают скалярные типы, поэтому теперь доступны следующие типы: self, array, callable, bool, float, int, string. Первые три были доступны в PHP 5, но последние четыре появились в PHP 7. Если вы используете что-нибудь еще (например, integer или boolean), это будет интерпретироваться как имя класса.

Дополнительную информацию см. в руководстве по PHP.

person TwoStraws    schedule 28.04.2016

Может быть, небезопасно и красиво, но если нужно:

class string
{
    private $Text;
    public function __construct($value)
    {
        $this->Text = $value;
    }

    public function __toString()
    {
        return $this->Text;
    }
}

function Test123(string $s)
{
    echo $s;
}

Test123(new string("Testing"));
person Patrick    schedule 13.07.2011
comment
Я все еще могу создать new string(array(1,2,3)) - person Jimmy T.; 22.08.2013

Я получил эту ошибку при вызове функции из контроллера Laravel в файл PHP.

Через пару часов я обнаружил проблему: я использовал $ this из статической функции.

person ecairol    schedule 18.03.2016
comment
Using $this when not in object context - действительно загадочное сообщение. - person Ben Fransen; 15.06.2017

(первоначально опубликовано leepowers в его вопросе)

Сообщение об ошибке сбивает с толку по одной большой причине:

Имена примитивных типов не зарезервированы в PHP

Ниже приведены все допустимые объявления классов:

class string { }
class int { }
class float { }
class double { }

Моя ошибка заключалась в том, что я думал, что сообщение об ошибке относится исключительно к строковому примитивному типу - слово «экземпляр» должно было заставить меня задуматься. Пример для дальнейшей иллюстрации:

class string { }
$n = 1234;
$s1 = (string)$n;
$s2 = new string();
$a = array('no', 'yes');
printf("\$s1 - primitive string? %s - string instance? %s\n",
        $a[is_string($s1)], $a[is_a($s1, 'string')]);
printf("\$s2 - primitive string? %s - string instance? %s\n",
        $a[is_string($s2)], $a[is_a($s2, 'string')]);

Вывод:

$ s1 - примитивная строка? да - экземпляр строки? нет

$ s2 - примитивная строка? нет - экземпляр строки? да

В PHP string может быть string, за исключением случаев, когда на самом деле это string. Как и в любом языке, использующем неявное преобразование типов, контекст - это все.

person Community    schedule 04.06.2018

Я думаю, что приведение типов на php внутри блока, String на PHP не является объектом, как я знаю:

<?php
function phpwtf($s) {
    $s = (string) $s;
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");
person subosito    schedule 05.11.2010
comment
Вы можете добавить проверку is_string () внутри своей функции, чтобы предотвратить передачу в функцию другого значения. - person subosito; 05.11.2010
comment
(string) $s может выдать ошибку, если $s - объект, который не может быть преобразован в строку (не реализован __toString() метод), поэтому это не так просто - person Yanick Rochon; 05.11.2010
comment
Да Яник, ты прав. Но мы не можем заставить весь ввод быть строкой, верно? вот почему в игру вступает исключение. Мы можем комбинировать проверки и перехватить исключение для остальных;) - person subosito; 05.11.2010
comment
Я просто говорю, что следует избегать преобразования некоторой переменной в строку без предварительной проверки, можно ли преобразовать переменную, в основном потому, что перехват исключений является дорогостоящим и приводит к плохим шаблонам проектирования / привычкам кодирования. - person Yanick Rochon; 05.11.2010