Эмуляция класса структуры типа значения в PHP


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

И если да, то какие другие методы можно было бы использовать? Какая лучшая техника?

Если это возможно, вы, очевидно, могли бы создать полностью типобезопасный слой для PHP, существуют ли такие слои? У кого-нибудь был какой-либо опыт в этом?

Author: NDM, 2009-09-28

4 answers

Объекты всегда передаются по ссылке. Единственный способ сделать так, чтобы они передавались как копия, - это явно использовать ключевое слово clone (да, везде).

Моя рекомендация состояла бы в том, чтобы использовать массив, который является типами значений и, следовательно, всегда копируется. Поскольку вы можете использовать его как ассоциативный массив (например, строка -> значение), он также может быть объектом. Недостатком, конечно, является то, что вы не можете использовать методы (но это похоже на структуру, так что вы можете быть довольны этим). Нет никакого способа обеспечить безопасность типов, однако.

Но при всех ваших требованиях, честно говоря, похоже, что PHP - это не ваш язык.

 1
Author: ryeguy, 2009-09-28 12:41:44

Я думаю, что самый простой способ сделать это так, как это делает java - пусть ваши классы значений будут неизменяемыми, и пусть все методы "модификации" вместо этого возвращают новый объект.

 1
Author: Anonymous, 2009-09-28 12:31:07

Я не думаю, что вы можете достичь этой цели, только с помощью PHP-кода.

У вас нет контроля над тем, как функции PHP обрабатывают параметры, и я не вижу, как вы могли бы убедиться, что все обрабатывается так, как вы хотите, без необходимости изменять (низкоуровневый) код в двоичном файле PHP и модулях.

Хотя это было бы довольно круто:)

 1
Author: Nicolas, 2009-09-28 12:41:25

Я играл с предложением анонима, чтобы любые мутации объекта возвращали новый объект, и это работает, но это неудобно.

<?php
class FruityEnum {
    private $valid = array("apple", "banana", "cantaloupe");
    private $value;

    function __construct($val) {
        if (in_array($val, $this->valid)) {
            $this->value = $val;
        } else {
            throw new Exception("Invalid value");
        }
    }

    function __set($var, $val) {
        throw new Exception("Use set()!!");
    }
    function set(FruityEnum &$obj, $val) {
        $obj = new FruityEnum($val);
    }

    function __get($var) { //everything returns the value...
        return $this->value;
    }
    function __toString() {
        return $this->value;
    }
}

А теперь, чтобы проверить это:

function mutate(FruityEnum $obj) { // type hinting!
    $obj->set($obj, 'banana');
    return $obj;
}

$x = new FruityEnum('apple');
echo $x; // "apple"
$y = mutate($x);
echo  $x // still "apple"
    . $y // "banana"

Это работает, но вам придется использовать странный способ изменения объекта:

$obj->set($obj, 'foo');

Единственным другим способом, который я мог придумать, было бы использовать метод __set(), но это было еще хуже. Ты должен был это сделать, что чертовски сбивает с толку.

$obj = $obj->blah = 'foo';

В конце концов, наверное, проще сделайте переменные закрытыми и не предоставляйте мутаторов, поэтому единственный способ изменить значение переменной "перечисление" - создать новое:

echo $obj; // "banana"
$obj = new FruityEnum("cantaloupe");
 1
Author: nickf, 2009-09-28 13:11:30