简体   繁体   English

有没有办法强制函数参数“不可更改”?

[英]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)
//}

The above code shows PHP object parameters are passed by reference.上面的代码显示 PHP 对象参数是通过引用传递的。 This results in a dilemma that, by looking at a function's signature, one does not know whether the parameters are changed in the function.这导致了一个困境,即通过查看函数的签名,人们不知道函数中的参数是否发生了变化。 This means one have to read the whole function just to find out whether the parameter is changed, which makes the whole code less readable and more bug-prone.这意味着必须阅读整个函数才能确定参数是否更改,这使得整个代码的可读性降低并且更容易出错。

Is there a way to "systematically assure the code reader" that an object parameter cannot be changed inside a function?有没有办法“系统地确保代码阅读器”不能在函数内部更改对象参数? I have though of adding more comments but comments can sometimes differ from what the code actually does and when that happens it becomes even harder to debug.虽然我有添加更多注释,但注释有时可能与代码实际所做的不同,当这种情况发生时,调试变得更加困难。

Workarounds are acceptable, but I would like something that will only affect some specific parameters of some specific functions and not others, in a human-readable fashion.变通办法是可以接受的,但我希望以人类可读的方式只影响某些特定函数的某些特定参数而不影响其他参数。

Essentially the following effect is what I want:基本上以下效果是我想要的:

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);

Although there isn't any builtin way to do this in PHP, you can make use of a workaround.尽管在 PHP 中没有任何内置方法可以做到这一点,但您可以使用一种解决方法。

You can use debug_backtrace to get the call trace when the method setA() is being called.当调用setA()方法时,您可以使用debug_backtrace获取调用跟踪。 If the result includes any class name being called in other than the host class, you can throw an exception for immutability.如果结果包括在宿主类之外调用的任何类名,您可以抛出一个异常以保证不变性。

Snippet:片段:

<?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);

Online Demo在线演示

Note: This only applies to Foo objects willing to be immutable inside another class methods and not otherwise.注意:这仅适用于愿意在另一个类方法中不可变的Foo对象,而不适用于其他方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM