ArrayAccess

ArrayAccess(数组式访问)接口

提供像访问数组一样访问对象的能力的接口。

继承 ArrayObject 可以直接拥有数组能力,无需自己实现

示例1

class Obj implements ArrayAccess
{
    private $container = [];
    public function __construct()
    {
        $this->container = [
            'one' => 1,
            'two' => 2,
            'three' => 3
        ];
    }
    // 获取一个偏移位置的值 $obj['two'];
    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }
    // 设置一个偏移位置的值 $obj['two'] = 1;
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }
    // 检查一个偏移位置是否存在 isset()
    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }
    // 复位一个偏移位置的值 unset()
    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }
}

$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';
var_dump($obj);

/*
bool(true)

int(2)

bool(false)

string(7) "A value"

class Obj#1 (1) {
  private $container =>
  array(6) {
    'one' =>
    int(1)
    'three' =>
    int(3)
    'two' =>
    string(7) "A value"
    [0] =>
    string(8) "Append 1"
    [1] =>
    string(8) "Append 2"
    [2] =>
    string(8) "Append 3"
  }
}
*/

示例2

<?php

namespace XxlJob\Dto;

class RunRequestDto
{
    private array $container;

    /**
     * @param int $jobId 任务ID
     * @param string $executorHandler 执行器Handler
     * @param ?string $executorParams 执行器参数, Nullable string.
     * @param string $executorBlockStrategy 执行器阻塞策略
     * @param int $executorTimeout 执行器超时时间 (秒)
     * @param int $logId 日志ID
     * @param int $logDateTime 日志时间 (Unix timestamp)
     * @param string $glueType Glue类型
     * @param ?string $glueSource Glue源码, Nullable string.
     * @param int $glueUpdatetime Glue更新时间 (Unix timestamp)
     * @param int $broadcastIndex 广播索引
     * @param int $broadcastTotal 广播总数
     */
    public function __construct(
        public int     $jobId = 0,
        public string  $executorHandler = '',
        public ?string $executorParams = null,
        public string  $executorBlockStrategy = '',
        public int     $executorTimeout = 0,
        public int     $logId = 0,
        public int     $logDateTime = 0,
        public string  $glueType = '',
        public ?string $glueSource = null,
        public int     $glueUpdatetime = 0,
        public int     $broadcastIndex = 0,
        public int     $broadcastTotal = 0
    )
    {
        $this->container = get_object_vars($this);
    }

    public function offsetGet($offset): mixed
    {
        return $this->container[$offset] ?? null;
    }

    public function offsetSet($offset, $value): void
    {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset): bool
    {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset): void
    {
        unset($this->container[$offset]);
    }
}

获取不带命名空间的类名

Laravel 源码里扒出来的 class_basename 辅助函数

basename(str_replace('\\', '/', $class));
# substr 实现

```php
substr(strrchr($class, "\\"), 1);
// or
substr($class, strrpos($class, '\\') + 1);

explode 实现

array_pop(explode('\\', $class));

ReflectionClass 实现

其中,ReflectionClass 是最快最保险的方案,但此类必须实际存在,不存在则会抛出 ReflectionException: Class \Foo\Bar does not exist。

(new \ReflectionClass($class))->getShortName();

定时执行脚本

while($change_records = $query->offset($offset)->limit($limit)->all()){
    foreach($change_records as $change_record){
        $log = [
            'tag' => 'RunChangeRecord',
            'attributes' => $change_record->attributes
        ];
        try{
            $change_record->run();
            $log['message'] = 'success';
        }catch(\Exception $e){
            $log['exception'] = [
                'code' => $e->getCode(),
                'message' => $e->getMessage(),
                'trace' => ErrException::getTraceString($e)
            ];
        }
        Yii::info($log, 'log');
    }
    $offset += $limit;
    usleep(10000); // 0.01秒一次
}