Увеличение на "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

Author: Baba, 2013-05-04

5 answers

Важен порядок, в котором выполняются операции:

  1. Переменная будет извлечена как объект, она не будет преобразована в целое число (или что-то еще).

  2. Этот оператор ++ увеличивает lval (длинное значение) zval, но обычно ничего другого не делает. Указатель на объект остается прежним. Внутренний (fast_)increment_function будет вызван с помощью zval, у которого есть указатель на объект, который сначала проверяет тип. Если это объект, то он ничего не делает. Поэтому, когда ваш zval является объектом, он так же полезен, как и отсутствие операции. Это не выведет никакого предупреждения.

  3. Только тогда инструкция echo выполняет приведение строки к его аргументам: Метод __toString вызывается и возвращает 20.

  4. 20 будет выводиться.

 12
Author: bwoebi, 2013-06-15 10:26:02

Чтобы ответить на ваш вопрос с помощью небольшого кода.

$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

Он преобразует ваш объект в строку, которая может быть преобразована в число для математической операции.

 9
Author: TheHippo, 2013-05-04 14:36:18

Я думаю, что было бы понятнее просто изменить имена переменных следующим образом:

class Group {
    private $number = 20;

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

$group = new Group();
echo $group;//print 20 as per your __toString function

++ $group;

Теперь кажется очевидным: что должен делать оператор '++' для объекта группы типов??

 2
Author: Frédéric Clausset, 2013-05-04 14:43:46

Почему бы тебе просто:

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

Я использую что-то подобное для форматирования смещений в таблицах.

 1
Author: CodeAngry, 2013-06-25 02:33:09

На самом деле это более выполнимо, чем вы думаете - просто нужно сделать немного больше приведения типов, следующим образом:

<?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.

 0
Author: slevy1, 2013-11-08 04:48:57