You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否向PHP魔术方法__get()传递数组?

能否向PHP的__get()魔术方法传递数组?

首先直接给你结论:你没法直接向__get()传递数组,而且你写的$book->("name", "pages"])这种调用语法完全无效,PHP会直接抛出语法错误。

为什么你的代码行不通?

咱们一步步拆解问题:

  1. __get()的参数天生只能是字符串:PHP里__get()只有在你访问「不存在/不可访问的对象属性」时才会触发,它的唯一参数$name只能是字符串——因为对象的属性名本身就是字符串类型,根本不存在“数组属性名”这种东西,所以你代码里的is_array($name)判断永远不会成立。
  2. __set()方法存错地方了:你在__set()里用了局部变量$book_list,这会导致你设置的属性根本没存到类的$book_details里,应该改成$this->book_details[$name] = $value;才行。
  3. 调用语法完全不符合PHP规范:$book->("name", "pages"])这种写法完全不对,PHP里访问对象属性的正确方式是$book->属性名,属性名要么是合法标识符,要么用花括号包裹字符串(比如$book->{"my-property"}),但绝对不能是数组。

怎么实现批量获取属性的需求?

如果你想一次性拿多个属性,又不想额外写普通方法,这里给你两个贴近需求的方案:

方案1:用特殊格式的属性名触发批量获取

修改__get(),让它识别逗号分隔的属性列表,比如:

<?php // Book.php
class Book{
    /**
     * 存储书籍详情
     * @var array
     */
    private $book_details = [];

    function __set($name, $value) {
        // 修复__set的错误,把值存在实例的属性里
        $this->book_details[$name] = $value;
    }

    function __get($name) {
        // 判断是否是逗号分隔的属性列表
        if (str_contains($name, ',')) {
            $collect_info = [];
            $keys = explode(',', $name);
            foreach ($keys as $key) {
                $key = trim($key);
                if (isset($this->book_details[$key])) {
                    $collect_info[$key] = $this->book_details[$key];
                }
            }
            return $collect_info;
        } else {
            // 加上?? null避免不存在的属性报错
            return $this->book_details[$name] ?? null;
        }
    }
}

然后在resources.php里这么用:

<?php // resources.php
require_once "Book.php";
$book = new Book();
$book->name = "Somebook's Name";
$book->author = "This awesome dude";
$book->pages = "723";
$book->about = "Programming Content";

echo $book->name; // 输出 Somebook's Name
print_r($book->{"name,pages"}); // 输出 Array( [name] => Somebook's Name, [pages] => 723 )

方案2:实现ArrayAccess接口(类似魔术方法的扩展)

如果你想直接用数组下标来传数组获取属性,可以实现PHP的ArrayAccess接口,这样既能像普通对象一样用->访问属性,又能像数组一样用[]操作,还能处理数组类型的下标:

<?php // Book.php
class Book implements ArrayAccess{
    private $book_details = [];

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

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

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

    public function offsetGet($offset): mixed {
        // 这里可以直接处理数组类型的offset
        if (is_array($offset)) {
            $collect_info = [];
            foreach ($offset as $key) {
                if (isset($this->book_details[$key])) {
                    $collect_info[$key] = $this->book_details[$key];
                }
            }
            return $collect_info;
        } else {
            return $this->book_details[$offset] ?? null;
        }
    }

    // 保留__get和__set,兼容原来的属性访问方式
    function __set($name, $value) {
        $this->offsetSet($name, $value);
    }

    function __get($name) {
        return $this->offsetGet($name);
    }
}

调用的时候就可以这么写:

<?php // resources.php
require_once "Book.php";
$book = new Book();
$book->name = "Somebook's Name";
$book->author = "This awesome dude";
$book->pages = "723";
$book->about = "Programming Content";

echo $book->name; // 输出 Somebook's Name
print_r($book[["name", "pages"]]); // 输出 Array( [name] => Somebook's Name, [pages] => 723 )

最后总结下

  • 直接给__get()传数组是不可能的,因为它的参数只能是字符串;
  • 你原来的调用语法有严重错误,PHP不支持;
  • 可以通过约定特殊属性名或者实现ArrayAccess接口来实现批量获取属性的需求。

内容的提问来源于stack exchange,提问作者CovertX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:46:31