php 中对象/关联数组的解构赋值
Destructuring assignment in php for objects / associative arrays
在 CoffeeScript、Clojure、ES6 和许多其他语言中,我们对 objects/maps/etc 进行解构,有点像这样:
obj = {keyA: 'Hello from A', keyB: 'Hello from B'}
{keyA, keyB} = obj
我在 php 中找到了 list
function,它可以让你像这样解构数组:
$info = array('coffee', 'brown', 'caffeine');
list($drink, $color, $power) = $info;
有没有办法解构 PHP 中的对象或关联数组?如果不在核心库中,也许有人写了一些智能辅助函数?
对于 PHP 7.0 及更低版本,list
的功能不可用。文档状态:
list only works on numerical arrays and assumes the numerical indices start at 0.
extract()
函数可以满足您的目的,它可以将数组中的变量导入当前交易品种 table。虽然使用 list
您可以明确定义变量名称,但 extract()
不会给您这种自由。
提取关联数组
使用 extract
你可以做这样的事情:
<?php
$info = [ 'drink' => 'coffee', 'color' => 'brown', 'power' => 'caffeine' ];
extract($info);
var_dump($drink); // string(6) "coffee"
var_dump($color); // string(5) "brown"
var_dump($power); // string(8) "caffeine"
提取对象
提取对象的工作原理几乎相同。由于 extract
只接受一个数组作为参数,我们需要将对象属性作为数组获取。 get_object_vars
会为您做到这一点。它 returns 一个关联数组,所有 public 属性作为键,它们的值作为值。
<?php
class User {
public $name = 'Thomas';
}
$user = new User();
extract( get_object_vars($user) );
var_dump($name); // string(6) "Thomas"
陷阱
extract()
与 list
不同,因为它不允许您显式定义导出到符号 table 的变量名。变量名默认对应数组键
list
是一种语言结构,而 extract()
是一种函数
- 您可能会无意中覆盖您事先定义的变量
- 您的数组键作为变量名可能无效
使用可以作为第二个参数传递给 extract()
的 $flags
参数,您可以在发生冲突或无效变量时影响行为。但了解 extract()
的工作原理并谨慎使用它仍然很重要。
编辑:从 PHP 7.1 开始,这是可能的:
You can now specify keys in list(), or its new shorthand [] syntax. This enables destructuring of arrays with non-integer or non-sequential keys.
The shorthand array syntax ([]) may now be used to destructure arrays for assignments (including within foreach), as an alternative to the existing list() syntax, which is still supported.
例如这个:
$test_arr = ['a' => 1, 'b' => 2];
list('a' => $a, 'b' => $b) = $test_arr;
var_dump($a);
var_dump($b);
从 7.1.0 开始将输出以下内容
int(1)
int(2)
可变变量是实现此目的的一种方法:
$args = ['a' => 1, 'b' => 2, 'c' => 3];
foreach (['a', 'c'] as $v) $$v = $args[$v];
// $a is 1, $b is undefined, $c is 3
它真的不漂亮,幸好 https://wiki.php.net/rfc/short_list_syntax 在 7.1 中解决了这个问题。这会让你在上面的例子中说 ['a' => $a, 'c' => $c] = $args;
。
因为 7.1 包含一种方法,可以为您的 var 使用与 assoc 数组键不同的名称。这也非常简单,在这里使用可变变量:
foreach (['a' => 'eh', 'b' => 'bee'] as $k => $v) $$v = $args[$k];
// $eh is 1, $bee is 2
一些开发人员和一些编码风格将 $$var
定义为类似于直接使用 eval
、extract
和 GPR
魔术变量的反模式。这是因为使用可变变量会使代码更难理解,这会直接导致错误并阻止静态代码分析工具发挥作用。
如果您确实采用了 $$var
,那么使用 ${$var}
形式会有所帮助,这很明显作者并没有简单地键入太多 $,并且当他们的代码被审核时,可以免除作者的即时负面反馈。
我注意到已接受的答案遗漏了使用速记符号的示例、使用提取的安全问题和 IDE 问题。
数值数组解构(PHP 7.1)
从 PHP 7.1 开始支持数值数组解构 (Symetric array destructuring),如下所示:
<?php
$data = [55, 'John', 'UK'];
[$id, $name] = $data; // short-hand (recommended)
list($id, $name) = $data; // long-hand
请注意,如果您不想要它们,您可能会错过它们。
关联数组解构(PHP 7.1)
您也可以解构关联数组 (Support for keys in list),如下所示:
<?php
$data = ['id' => 55, 'firstName' => 'John', 'country' => 'UK']
['id' => $id, 'firstName' => $name] = $data; // short-hand (recommended)
list('id' => $id, 'firstName' => $name) = $data; // long-hand
请注意,如果您不想要它们,您可能会错过它们。变量名称也可以与 属性 名称不同。
对象解构(PHP 7.1)
不幸的是没有对象解构。但是,您可以使用 get_object_vars
将对象转换为关联数组,然后使用关联数组解构。
<?php
class User {
public $id;
public $name;
public $country;
}
$user = new User();
$user->id = 55;
$user->name = 'John';
$user->country = 'UK';
['id' => $id, 'firstName' => $name] = get_object_vars($user)
但是,这可能会破坏某些 IDE 功能。这些是我在使用 PHPStorm 2019.1 时注意到的一些问题:
- IDE 可能不再理解变量的类型,因此您需要添加一些
@var Type
PHP文档来维护自动完成功能
- 不适用于重构工具。例如,如果您重命名其中一个属性,则数组解构部分不会自动重命名。
所以我建议以正常方式进行:
$id = $user->id
$name = $user->firstName
不要使用 extract
使用 extract,始终设置所有变量。使用它是一个非常糟糕的主意,因为:
- 这可能会导致安全问题。即使你很小心,它也可能在未来导致不明显的安全漏洞。如果您确实使用它,请不要将其与用户输入一起使用(例如
$_GET
、$_POST
),除非您想成为恶意黑客的一天。
- 可能导致难以检测的错误
- 如果 class 或数组在未来发生变化,通过引入新属性,如果它与已使用的变量重合,它可能会破坏您的代码,除非您使用
EXTR_SKIP
标志或类似的
在 CoffeeScript、Clojure、ES6 和许多其他语言中,我们对 objects/maps/etc 进行解构,有点像这样:
obj = {keyA: 'Hello from A', keyB: 'Hello from B'}
{keyA, keyB} = obj
我在 php 中找到了 list
function,它可以让你像这样解构数组:
$info = array('coffee', 'brown', 'caffeine');
list($drink, $color, $power) = $info;
有没有办法解构 PHP 中的对象或关联数组?如果不在核心库中,也许有人写了一些智能辅助函数?
对于 PHP 7.0 及更低版本,list
的功能不可用。文档状态:
list only works on numerical arrays and assumes the numerical indices start at 0.
extract()
函数可以满足您的目的,它可以将数组中的变量导入当前交易品种 table。虽然使用 list
您可以明确定义变量名称,但 extract()
不会给您这种自由。
提取关联数组
使用 extract
你可以做这样的事情:
<?php
$info = [ 'drink' => 'coffee', 'color' => 'brown', 'power' => 'caffeine' ];
extract($info);
var_dump($drink); // string(6) "coffee"
var_dump($color); // string(5) "brown"
var_dump($power); // string(8) "caffeine"
提取对象
提取对象的工作原理几乎相同。由于 extract
只接受一个数组作为参数,我们需要将对象属性作为数组获取。 get_object_vars
会为您做到这一点。它 returns 一个关联数组,所有 public 属性作为键,它们的值作为值。
<?php
class User {
public $name = 'Thomas';
}
$user = new User();
extract( get_object_vars($user) );
var_dump($name); // string(6) "Thomas"
陷阱
extract()
与 list
不同,因为它不允许您显式定义导出到符号 table 的变量名。变量名默认对应数组键
list
是一种语言结构,而extract()
是一种函数- 您可能会无意中覆盖您事先定义的变量
- 您的数组键作为变量名可能无效
使用可以作为第二个参数传递给 extract()
的 $flags
参数,您可以在发生冲突或无效变量时影响行为。但了解 extract()
的工作原理并谨慎使用它仍然很重要。
编辑:从 PHP 7.1 开始,这是可能的:
You can now specify keys in list(), or its new shorthand [] syntax. This enables destructuring of arrays with non-integer or non-sequential keys.
The shorthand array syntax ([]) may now be used to destructure arrays for assignments (including within foreach), as an alternative to the existing list() syntax, which is still supported.
例如这个:
$test_arr = ['a' => 1, 'b' => 2];
list('a' => $a, 'b' => $b) = $test_arr;
var_dump($a);
var_dump($b);
从 7.1.0 开始将输出以下内容
int(1)
int(2)
可变变量是实现此目的的一种方法:
$args = ['a' => 1, 'b' => 2, 'c' => 3];
foreach (['a', 'c'] as $v) $$v = $args[$v];
// $a is 1, $b is undefined, $c is 3
它真的不漂亮,幸好 https://wiki.php.net/rfc/short_list_syntax 在 7.1 中解决了这个问题。这会让你在上面的例子中说 ['a' => $a, 'c' => $c] = $args;
。
因为 7.1 包含一种方法,可以为您的 var 使用与 assoc 数组键不同的名称。这也非常简单,在这里使用可变变量:
foreach (['a' => 'eh', 'b' => 'bee'] as $k => $v) $$v = $args[$k];
// $eh is 1, $bee is 2
一些开发人员和一些编码风格将 $$var
定义为类似于直接使用 eval
、extract
和 GPR
魔术变量的反模式。这是因为使用可变变量会使代码更难理解,这会直接导致错误并阻止静态代码分析工具发挥作用。
如果您确实采用了 $$var
,那么使用 ${$var}
形式会有所帮助,这很明显作者并没有简单地键入太多 $,并且当他们的代码被审核时,可以免除作者的即时负面反馈。
我注意到已接受的答案遗漏了使用速记符号的示例、使用提取的安全问题和 IDE 问题。
数值数组解构(PHP 7.1)
从 PHP 7.1 开始支持数值数组解构 (Symetric array destructuring),如下所示:
<?php
$data = [55, 'John', 'UK'];
[$id, $name] = $data; // short-hand (recommended)
list($id, $name) = $data; // long-hand
请注意,如果您不想要它们,您可能会错过它们。
关联数组解构(PHP 7.1)
您也可以解构关联数组 (Support for keys in list),如下所示:
<?php
$data = ['id' => 55, 'firstName' => 'John', 'country' => 'UK']
['id' => $id, 'firstName' => $name] = $data; // short-hand (recommended)
list('id' => $id, 'firstName' => $name) = $data; // long-hand
请注意,如果您不想要它们,您可能会错过它们。变量名称也可以与 属性 名称不同。
对象解构(PHP 7.1)
不幸的是没有对象解构。但是,您可以使用 get_object_vars
将对象转换为关联数组,然后使用关联数组解构。
<?php
class User {
public $id;
public $name;
public $country;
}
$user = new User();
$user->id = 55;
$user->name = 'John';
$user->country = 'UK';
['id' => $id, 'firstName' => $name] = get_object_vars($user)
但是,这可能会破坏某些 IDE 功能。这些是我在使用 PHPStorm 2019.1 时注意到的一些问题:
- IDE 可能不再理解变量的类型,因此您需要添加一些
@var Type
PHP文档来维护自动完成功能 - 不适用于重构工具。例如,如果您重命名其中一个属性,则数组解构部分不会自动重命名。
所以我建议以正常方式进行:
$id = $user->id
$name = $user->firstName
不要使用 extract
使用 extract,始终设置所有变量。使用它是一个非常糟糕的主意,因为:
- 这可能会导致安全问题。即使你很小心,它也可能在未来导致不明显的安全漏洞。如果您确实使用它,请不要将其与用户输入一起使用(例如
$_GET
、$_POST
),除非您想成为恶意黑客的一天。 - 可能导致难以检测的错误
- 如果 class 或数组在未来发生变化,通过引入新属性,如果它与已使用的变量重合,它可能会破坏您的代码,除非您使用
EXTR_SKIP
标志或类似的