Я не уверен, что должно быть в заголовке, но код должен объяснить это лучше:
class Group { private $number = 20; public function __toString() { return "$this->number"; } } $number = new Group(); echo $number, PHP_EOL; echo ++ $number, PHP_EOL; echo PHP_EOL; $number = "20"; echo $number, PHP_EOL; echo ++ $number, PHP_EOL; echo PHP_EOL; $number = 20; echo $number, PHP_EOL; echo ++ $number, PHP_EOL;
Вывод:
20 20 <--- Expected 21 20 21 20 21
Любая идея, почему я получил 20
вместо 21
? Даже тогда код ниже работает:
$i = null ; echo ++$i ; // output 1
Я знаю, что Group
– это объект, который реализует __toString
, я ожидал, что ++
работает со строкой из __toString
или, по крайней мере, throw an error
Порядок, в котором происходят операции, важен:
Переменная будет выбрана как объект, она не будет передана в целое число (или что-то еще).
Этот оператор ++
увеличивает lval
(длинное значение) zval
, но обычно ничего не делает. Указатель объекта остается неизменным. Внутренняя (fast_)increment_function
будет вызываться с zval
которая имеет указатель на объект, который сначала проверяет тип. Если это объект, он ничего не делает. Поэтому, когда ваш zval
является объектом, он так же полезен, как и без операции. Это не выдаст никаких предупреждений.
Только тогда команда echo выполняет строку, отличную от его аргументов: вызывается метод __toString
и возвращает 20
.
20
будет выводиться.
Чтобы ответить на вопрос с небольшим количеством кода.
$number = new Group(); echo gettype($number); $number = "20"; echo gettype($number); $number = 20; echo gettype($number);
В результате
object string integer
Три случая:
__toString
будет вызван очень поздно, когда вычисляется acutal-вывод, после того как вы безуспешно попытались выполнить математическую операцию с ним. Бонус:
Это будет работать:
$number = new Group(); echo 1 + "$number"; // 21
Он преобразует объект в строку, которая может быть преобразована в число для математической операции.
Я думаю, что может быть яснее, просто изменив имена таких переменных:
class Group { private $number = 20; public function __toString() { return "$this->number"; } } $group = new Group(); echo $group;//print 20 as per your __toString function ++ $group;
Теперь кажется очевидным: что должен делать оператор «++» на объекте группы типов?
Почему бы вам не просто:
class Group { private $number = 0; public function __construct($number = 0){ $this->number = intval($number); } public function __toString() { return number_format(++$this->number); // pre-increment } } $g = new Group(); echo $g; // 1 echo $g; // 2
Я использую что-то подобное для форматирования смещений в таблицах.
Это на самом деле более осуществимо, чем вы можете подумать – просто нужно сделать немного больше литья типов, как показано ниже:
<?php class Group { private $number = 20; public function __toString() { return (string) $this->number; // replace "" w/string cast } } $number = (int)(string) new Group(); echo $number, PHP_EOL; echo ++$number, PHP_EOL;
Разумеется, вам не нужно использовать строчную трансляцию в магии __toString (), но я лично предпочитаю читать код таким образом, а не видеть кавычки, но я думаю, что это просто стилистическая предпочтения.
Приведение вновь созданного объекта в виде строки приводит к автоматическому выполнению метода магии __toString и возвращает числовую строку, которая при нажатии на int позволяет отображать число, увеличивать его и отображать снова.
Между прочим, пространство между ++ и $ number в порядке; Я закрыл его b / c, и это то, к чему я привык на других языках, таких как C.