PHP内置接口ArrayAccess:像使用数组一样使用类

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"
}
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值