Увеличение на "toString"
Я не уверен, каким должно быть название, но код должен лучше объяснить это:
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
5 answers
Важен порядок, в котором выполняются операции:
Переменная будет извлечена как объект, она не будет преобразована в целое число (или что-то еще).
Этот оператор
++
увеличивает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
будет вызван очень поздно, когда будет вычислен точный вывод, после того как вы безуспешно попытались выполнить с ним математическую операцию. - Вы можете выполнять математику со строками, потому что PHP внутренне преобразует их обратно в числа
- Очевидно, что вы можете выполнять математику с целым числом
Бонус:
Это будет работать:
$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;
Вам, конечно, не обязательно использовать приведение строк в magic __toString(), но лично я предпочитаю читать код таким образом, а не видеть кавычки - но я думаю, что это просто стилистическое предпочтение.
Приведение вновь созданного объекта в виде строки приводит к автоматическому выполнению метода magic __toString и возвращает числовое значение строка, которая при приведении к значению int позволяет отображать число, увеличивать его и отображать снова.
Кстати, пространство между ++ и $number в порядке; Я закрыл его b/c, это то, к чему я привык в других языках, таких как C.