提问人:Fawfulcopter 提问时间:11/17/2023 最后编辑:Fawfulcopter 更新时间:11/17/2023 访问量:57
PHP 通过引用返回数组,但也可为 null
PHP return arrays by reference, but also be nullable
问:
我是 JavaScript 的 Array.prototype.find()
的忠实粉丝。我喜欢能够只接受一个数组,给它抛出一个谓词,然后获取该数组中与谓词匹配的第一个元素。我希望在PHP中以辅助函数的形式实现该功能。
这是我想出的:
function find(array &$arr, callable $callable)
{
foreach ($arr as &$x) {
if ($callable($x)) {
return $x;
}
}
return null;
}
这很好用。主要。我很难获得我想要的关于引用的确切行为。也就是说,如果返回的元素是一个复杂的结构(即,它是一个对象或数组),并且我通过调用返回值的实例方法或键来修改该元素结构的内容,则更改应立即反映在我从中提取它的数组中。这是 JavaScript 的原生行为,我希望我的 PHP 端口完全模拟这一点。
如果正在迭代的数组充满了对象,则此操作完美无缺。PHP 默认传递对对象的引用,所以这不是问题。
当迭代数组充满嵌套子数组时,我的问题就出现了。如果我从这个函数得到一个子数组值,它就会被值传递并复制。如果调用方修改找到的子数组的副本,则更改不会反映在父数组中。
好的,所以,简单的修复,对吧?只需将 & 符号放在函数定义上即可。.容易。&find(...)
但这个函数的本质是,有时它找不到与谓词匹配的元素。所以它有时必须返回。当与按引用返回函数定义结合使用时,这会引发一个:NULL
E_NOTICE
PHP 注意:在 [stacktrace] 中,只有变量引用应该通过引用返回
我可以通过在函数中定义一个 null 变量并返回对该变量的引用来阻止通知,但这感觉就像代码味道。简单地抑制通知也是如此。我宁愿不做其中任何一个,除非我能充分确信这是首选的成语。
显然我做了一些不正确的事情,但我不确定解决方案应该是什么。我在这里错过了更好的模式吗?
编辑:此假设函数的预期用法示例:
$main_array = [
[ 'key' => 10 ],
[ /* stuff */ ],
[ /* stuff */ ],
// ...
];
// Raises E_NOTICE if null
$sub_array =& find(
$main_array,
fn($x) => $x['key'] === 10
);
if (!$sub_array) {
// handle null case as appropriate
}
// Modify substructure of returned value
$sub_array['key'] = 20;
// Changed value should reflect in main array:
echo $main_array[0]['key'] === 20 ? 'True' : 'False';
// True
答:
显然我做错了什么
我认为这根本不明显:在 PHP 中,引用是变量之间的链接;因此,如果要使用引用,则必须使用变量。正如你已经发现的,这意味着要通过引用返回一个,你需要将一个变量设置为first。换言之,必须先使用值赋值 (),然后才能使用引用赋值 ()。null
null
$foo = null
$bar =& $foo
默认情况下,PHP 传递对对象的引用
需要注意的是,这与引用分配的意义不同。请考虑以下代码:=&
$arr = [new class{}];
$foo = find($arr, fn($item) => true);
$foo->someProp = 'hello';
$foo = 42;
var_dump($arr);
该数组仍然包含原始对象,但该对象现在将在其属性中具有 。变量不是引用,但对象是可变结构。$arr
'hello'
$someProp
将第 2 行更改为 ,而是数组将包含值 ,并且对象将被销毁。变量本身是一个引用,是 的另一个名称,因此等价于$foo =& find(...
42
$arr[0]
$foo = 42;
$arr[0] = 42;
我在这里错过了更好的模式吗?
可以说,“更好”的模式就是不使用引用,这通常很令人困惑。如果需要可变值,请使用对象,而不是数组或其他类型。
请注意,JavaScript 行为不同的原因不是它默认使用类似于 PHP 引用的任何内容,而是因为在 JavaScript 中数组本身就是可变对象。
将上面的示例翻译成 JavaScript:
arr = [new Object];
foo = arr.find((item) => true);
foo.someProp = 'hello';
foo = 42;
console.log(arr);
与 PHP 一样,仍然包含已更改的对象; 不被视为对数组元素的直接引用。arr
foo
评论
$a = 1; $b = $a; $b++;
1
$a
$b
$a = []; $b = $a; $b[] = 42;
$foo =& $arr[0];
$arr[0] =& $foo;
unset($foo);
$a = []; $b = $a; $b[] = 42;
$a
$b
$a['key'] = 'value'
$a
$a
$a=1; $a++;
$a
$a=[]; $a['key'] = 'value';
$a
['key'=>'value']
[]
评论
this raises a notice
你能添加通知吗?您也可以添加代码,在何处以及如何访问该函数。find()