Интересно, можно ли сделать что-то вроде следующего (я знаю, что код не будет работать так, как задумано, просто пытаюсь донести цель):

class Form
{
    private $v = array();

    function __set($varName, $varValue)
    {
        ... do some treatment on the varValue ...
        $this->v[$varName] = $varValue;
    }

    function &__get($varName)
    {
        if(!isset($this->v[$varName]))
            $this->v[$varName] = NULL;

        return $this->v[$varName];
    }
};

Я хочу иметь возможность установить такую ​​переменную, как:

$form->Values['whatever'] = 'dirty';

И запустить его через функцию установки, которая вызовет некоторые операции очистки и фактически заполнит пару других массивов, таких как 'HtmlValues' и 'SqlValues', чтобы я мог просто вытащить значения, закодированные для нужного мне формата, чтобы позже я мог позвонить

echo $form->HtmlValues['whatever'];

Проблема, конечно, в том, что если вы просто используете _ get, вы в конечном итоге устанавливаете возвращаемое значение, и хотя & _get возвращает его по ссылке и что-то вроде работы, __set - это на самом деле никогда не вызывается, даже если вы устанавливаете частный член.

В общем, мне интересно, есть ли способ вызвать функцию для значения всякий раз, когда вы устанавливаете его в массиве (возможно, несколько массивов глубоких и что не нравится $form->Values['group']['item'] = 'whatever';

Желаемый результат будет примерно таким:

$form->Values['name'] = "&";
echo $form->HtmlValues['name']; = &

(Просто для подкрепления, я не ищу фактическую кодировку, а просто возможность вызывать ее для каждой переменной по мере ее установки / изменения без необходимости кодировать весь массив вручную)

php
6
John 9 Май 2011 в 20:19

3 ответа

Лучший ответ

Вы хотите реализовать интерфейс ArrayAccess. на связанной странице есть примеры того, как это сделать.

РЕДАКТИРОВАТЬ: Для облегчения доступа я включил пример с php.net ниже:

<?php
class obj implements arrayaccess {
    private $container = array();
    public function __construct() {
        $this->container = array(
            "one"   => 1,
            "two"   => 2,
            "three" => 3,
        );
    }
    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }
    public function offsetExists($offset) {
        return isset($this->container[$offset]);
    }
    public function offsetUnset($offset) {
        unset($this->container[$offset]);
    }
    public function offsetGet($offset) {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }
}

$obj = new obj;

var_dump(isset($obj["two"]));
var_dump($obj["two"]);
unset($obj["two"]);
var_dump(isset($obj["two"]));
$obj["two"] = "A value";
var_dump($obj["two"]);
$obj[] = 'Append 1';
$obj[] = 'Append 2';
$obj[] = 'Append 3';
print_r($obj);
?>
4
Jonathan Fingland 9 Май 2011 в 20:22

Взгляните на ArrayAccess.

1
Alin Purcaru 9 Май 2011 в 20:23

В этой ситуации я делаю так, чтобы __get() возвращал объект, расширяющий ArrayObject напрямую, а не массив.

private $v;
public function __construct()
{
  $this->v = new ArrayObject(); // or MyArrayObject()
  // repeat for each of your "arrays" you want to return
}

(Обратите внимание, что это отличается от реализации ArrayAccess непосредственно родительским классом, что также может быть полезно в других ситуациях.)

Вот пример:

<?php
class MyArrayObject extends ArrayObject
{
  private $validate;
  public function __construct($validate)
  {
    parent::__construct();
    $this->validate = $validate;
  }

  public function offsetSet($i, $v)
  {
    $validate = $this->validate;
    if (!$validate($this, $i, $v))
      throw new Exception();

    parent::offsetSet($i, $v);
  }
}

class Foo
{
  private $v;
  public function __construct()
  {
    $this->v = new MyArrayObject(function(MyArrayObject $me, $i, $v) {
      // only accept values that are larger than 5
      return $v > 5;
    });
  }

  public function __get($key)
  {
    if ($key == 'bar') return $this->v;
  }
}

$f = new Foo();
$f->bar[] = 10;
$f->bar[] = 5;   // throws exception
0
Matthew 9 Май 2011 в 20:40