开发者

Constant non-modifying object reference in PHP

开发者 https://www.devze.com 2023-02-22 14:10 出处:网络
This is not a question about real code, it is just for discussion. It looks to me that it would be niceto be able to pass an object as a constant reference.

This is not a question about real code, it is just for discussion. It looks to me that it would be nice to be able to pass an object as a constant reference.

$c = Coordinate;
unsafe_func($c); 开发者_StackOverflow社区// this should be ok
unsafe_func(... constant reference ... $c); // this should fail on write to $c

I know about an option to pass a clone of the object like set(clone $c) which will keep my original $c not modified by unsafe_func(), but what if I would like to have a single object instance?

What I came up with is a wrapper class (code: https://gist.github.com/904897) using __set() and __get() magic methods, throwing exception on every __set() call. It allows me to do this:

class CoordinateConst extends stdConst {};
unsafe_func(new CoordinateConst($c)); // exception: can not be modified!

What I do not like about the solution is that by introducing CoordinateConst, I have to remove Coordinate typehints. But if I extend Coordinate class, __set() method is not called for visible properties.

The question: Is there a more common way to do this or would you rather avoid such code for any case (by passing object clone, wrapping unsafe_func call or something else)?


You solution effectively prevents public properties from being written to. The coordinate would not be a constant reference if it had a function such as:

public function setX($x) {
    $this->x = $x;
}

An alternative (but more code depending on how often you want to do it), would be to create ReadOnly versions of the classes.

I know in Java and C# it's commonly applied to Collections. C# has a ReadOnlyCollection<T>, which is just a wrapper/proxy, much like you have done there.

So my approach to the problem would be to create:

class ReadOnlyCoordinate { 
    private $coordinate;

    public function __construct(Coordinate $coordinate) {
        $this->coordinate = $coordinate;
    }

    public function getX() {
        return $this->coordinate->getX();
    }

Of course, you could extend Coordinate, and then throw Exceptions on functions that set any properties.


Then looking at the issue overall, if you don't want Coordinate members/setters to be exposed to unsafe_func, then perhaps you could only send the required data. Which does of course depend on how much of the Coordinate data it requires.

e.g.

unsafe_func($coordinate->getRequiredData());

but then if you have a lot of data it requires, it would become a hassle.

0

精彩评论

暂无评论...
验证码 换一张
取 消