提问人:cr001 提问时间:7/5/2022 最后编辑:cr001 更新时间:7/5/2022 访问量:78
有没有办法强制函数参数“不可更改”?
Is there a way to force function parameter to be "unchangeable"?
问:
<?php
// Enter your code here, enjoy!
class Foo {
private $a;
public function getA() {
return $this->a;
}
public function setA($a) {
$this->a = $a;
}
}
class Bar {
public function test(Foo $f) {
$f->setA(2);
}
}
$foo = new Foo();
$foo->setA(1);
var_dump($foo);
$bar = new Bar();
$bar->test($foo);
var_dump($foo);
//output
//object(Foo)#1 (1) {
// ["a":"Foo":private]=>
// int(1)
//}
//object(Foo)#1 (1) {
// ["a":"Foo":private]=>
// int(2)
//}
上面的代码显示 PHP 对象参数是通过引用传递的。这导致了一个两难的境地,即通过查看函数的签名,人们不知道函数中的参数是否发生了变化。这意味着必须读取整个函数才能找出参数是否被更改,这使得整个代码的可读性降低并且更容易出错。
有没有办法“系统地向代码阅读者保证”对象参数不能在函数中更改?我虽然添加了更多注释,但注释有时可能与代码实际执行的操作不同,当这种情况发生时,调试变得更加困难。
解决方法是可以接受的,但我想要一些只会影响某些特定函数的某些特定参数,而不影响其他特定参数的东西,以人类可读的方式。
从本质上讲,以下效果是我想要的:
class Foo {
private $a;
public function getA() {
return $this->a;
}
public function setA($a) {
$this->a = $a;
}
}
class Bar {
public function test1(Foo $f1, Foo $f2) {
$f1->setA(2);
$f2->setA(2);
}
public function test2(Foo $f1, "immutable" Foo $f2) {
$f1->setA($f2->getA());
}
public function test3(Foo $f1, "immutable" Foo $f2) {
$f1->setA(3);
$f2->setA(3);
}
}
$foo1 = new Foo();
$foo2 = new Foo();
$bar = new Bar();
// This will work
$bar->test1($foo1,$foo2);
// This will also work
$bar->test2($foo1,$foo2);
// This will throw Exception / Or the $foo2 is unchanged outside the function without Exception is also fine
$bar->test3($foo1,$foo2);
答:
0赞
nice_dev
7/5/2022
#1
虽然在 PHP 中没有任何内置方法可以做到这一点,但您可以使用解决方法。
可以使用 debug_backtrace
在调用方法时获取调用跟踪。如果结果包括除主机类之外的任何类名,则可以引发不可变性异常。setA()
片段:
<?php
class Foo {
private $a;
public function getA() {
return $this->a;
}
public function setA($a) {
$current_class = get_class($this);
foreach(debug_backtrace() as $stack_trace){
if($stack_trace['class'] !== $current_class){
throw new Exception("$current_class object is immutable inside another class method!");
}
}
$this->a = $a;
}
}
class Bar {
public $f;
public function test(Foo $f) {
$f->setA(100);
}
}
$foo = new Foo();
$foo->setA(1);
$bar = new Bar();
$bar->test($foo);
注意:这仅适用于愿意在另一个类方法中不可变的对象,否则则不适用。Foo
评论
0赞
cr001
7/5/2022
我想在功能级别而不是在类级别上做到这一点。即 Bar 中的某些函数可能能够更改 $foo->a,但其他函数不能(并且函数签名将指示差异)。这是否也可以通过一些解决方法实现?
0赞
nice_dev
7/5/2022
@cr001 是的, 你可以的。你能让我知道函数名称吗,或者我应该在我的示例中添加它吗?在您的帖子中添加一些示例。test
0赞
cr001
7/5/2022
我们把它们称为 test 和 test2,我希望测试参数是不可变的,test2 参数是可变的。不过,我不希望它依赖于函数名称,而是想要一个“类似关键字”的系统,或者一个利用一些关键字级功能的解决方法。
0赞
cr001
7/5/2022
如果解决方法以某种方式绑定到参数并且仅绑定到参数(不影响其他参数和函数本身),那将是理想的。(类似于“&”说明符,但以另一种方式工作)
1赞
cr001
7/5/2022
确定。我将添加更多我想要的信息。
评论