class ab implements ArrayAccess{
/**
* Determine if the given attribute exists.
*
* @param mixed $offset
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->$offset);
}
/**
* Get the value for a given offset.
*
* @param mixed $offset
* @return mixed
*/
public function offsetGet($offset)
{
return $this->$offset;
}
/**
* Set the value for a given offset.
*
* @param mixed $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value)
{
$this->$offset = $value;
}
/**
* Unset the value for a given offset.
*
* @param mixed $offset
* @return void
*/
public function offsetUnset($offset)
{
unset($this->$offset);
}
/**
* 获取不存在属性
* @param $name
* @return null
*/
public function __get($name)
{
return null;
}
}
$ab = new ab;
$ab->a = 'a';
$ab['b'] = 'b';
echo "类属性方式获取" . PHP_EOL;
var_dump($ab->a, $ab->b, $ab->c);
echo "数组子健方式获取" . PHP_EOL;
var_dump($ab['a'], $ab['b'], $ab['c']);
echo "类" . PHP_EOL;
var_dump($ab);
/* 输出:
类属性方式获取
string(1) "a"
string(1) "b"
NULL
数组子健方式获取
string(1) "a"
string(1) "b"
NULL
类
object(ab)#3 (2) {
["a"]=>
string(1) "a"
["b"]=>
string(1) "b"
}
*/
更方便的写法,封装一个trait,然后类实现接口并使用统一的trait;如下:
下类支持数字键设置,上面的DEMO类不支持;
/**
* Trait ArrayAccessTrait
* @package App\Util
*/
trait ArrayAccessTrait
{
public $numOffset = 0;
/**
* Determine if the given attribute exists.
*
* @param mixed $offset
* @return bool
*/
public function offsetExists($offset): bool
{
return isset($this->$offset);
}
/**
* Get the value for a given offset.
*
* @param mixed $offset
* @return mixed
*/
public function offsetGet($offset)
{
return $this->$offset;
}
/**
* Set the value for a given offset.
*
* @param mixed $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
if (!isset($this->{$this->numOffset})) {
$this->{$this->numOffset} = $value;
$this->numOffset++;
} else {
$this->numOffset++;
$this->offsetSet($offset, $value);
}
} else {
$this->$offset = $value;
}
}
/**
* Unset the value for a given offset.
*
* @param mixed $offset
* @return void
*/
public function offsetUnset($offset)
{
unset($this->$offset);
}
/**
* 获取不存在属性
* @param $name
* @return null
*/
public function __get($name)
{
return null;
}
/**
* @return array
*/
public function toArray(): array
{
$attributes = get_object_vars($this);
unset($attributes['numOffset']);
return $attributes;
}
/**
* @param array $loadData
* @return static|null
*/
public static function loadArray(array $loadData): ?self
{
try {
$reflection = new ReflectionClass(__CLASS__);
if (!$reflection->isInstantiable()) {
return null;
}
$constructor = $reflection->getConstructor();
if (is_null($constructor)) {
return null;
}
$params = $constructor->getParameters();
if (count($params) == 0) {
return new self();
}
$keys = $values = [];
foreach ($params as $param) {
$key = $param->getName();
$keys[] = $key;
if (isset($loadData[$key])) {
$values[] = $loadData[$key];
continue;
}
if ($param->isDefaultValueAvailable()) {
$values[] = $param->getDefaultValue();
continue;
}
trigger_error("Not exists constructor parameters '{$key}' for class " . __CLASS__, E_USER_ERROR);
}
return $reflection->newInstanceArgs(array_combine($keys, $values));
} catch (Exception $exception) {
trigger_error($exception->getMessage(), E_USER_ERROR);
}
}
}
class ab implements ArrayAccess
{
use ArrayAccessTrait;
}
$ab = new ab;
$ab->a = 'a';
$ab['b'] = 'b';
$ab[] = 'c';
$ab[] = 'd';
$ab[2] = 'de';
$ab[3] = 'ef';
$ab[] = 'e';
$ab[99] = 'f';
echo "类属性方式获取" . PHP_EOL;
var_dump($ab->a, $ab->b, $ab->c, $ab->{0}, $ab->{'0'}, $ab->{99}, $ab->{100});
echo "数组子健方式获取" . PHP_EOL;
var_dump($ab['a'], $ab['b'], $ab['c'], $ab[0], $ab['0'], $ab[99], $ab[100]);
echo "类" . PHP_EOL;
var_dump($ab);
/* 输出:
类属性方式获取
string(1) "a"
string(1) "b"
NULL
string(1) "c"
string(1) "c"
string(1) "f"
NULL
数组子健方式获取
string(1) "a"
string(1) "b"
NULL
string(1) "c"
string(1) "c"
string(1) "f"
NULL
类
object(ab)#3 (9) {
["num"]=>
int(5)
["a"]=>
string(1) "a"
["b"]=>
string(1) "b"
["0"]=>
string(1) "c"
["1"]=>
string(1) "d"
["2"]=>
string(2) "de"
["3"]=>
string(2) "ef"
["4"]=>
string(1) "e"
["99"]=>
string(1) "f"
}
*/