能否向PHP魔术方法__get()传递数组?
能否向PHP的__get()魔术方法传递数组?
首先直接给你结论:你没法直接向__get()传递数组,而且你写的$book->("name", "pages"])这种调用语法完全无效,PHP会直接抛出语法错误。
为什么你的代码行不通?
咱们一步步拆解问题:
__get()的参数天生只能是字符串:PHP里__get()只有在你访问「不存在/不可访问的对象属性」时才会触发,它的唯一参数$name只能是字符串——因为对象的属性名本身就是字符串类型,根本不存在“数组属性名”这种东西,所以你代码里的is_array($name)判断永远不会成立。__set()方法存错地方了:你在__set()里用了局部变量$book_list,这会导致你设置的属性根本没存到类的$book_details里,应该改成$this->book_details[$name] = $value;才行。- 调用语法完全不符合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
相关产品推荐
相关产品推荐

