0

before Php 8.1 we could wrote that:

abstract class Base
{
    private $thing;

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

    protected function getThing()
    {
        return $this->thing;
    }
}

class Test1 extends Base
{
    private function needThing()
    {
        ... $this->getThing();
    }
}

class Test2 extends Base
{
    private function needThing()
    {
        ... $this->getThing();
    }
}

so getThing() was to get the inner thing object. It could have been written like that:

abstract class Base
{
    protected $thing;

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

class Test1 extends Base
{
    private function needThing()
    {
        ... $this->thing;
    }
}

class Test2 extends Base
{
    private function needThing()
    {
        ... $this->thing;
    }
}

it's shorter, does the same, but not $thing isn't really protected, it can be read and modified (the first example at least prevented from modifing). But here comes the readonly modifier:

abstract class Base
{
    readonly private $thing;

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

    protected function getThing()
    {
        return $this->thing;
    }
}

class Test1 extends Base
{
    private function needThing()
    {
        ... $this->thing;
    }
}

class Test2 extends Base
{
    private function needThing()
    {
        ... $this->thing;
    }
}

I think this is a serious game changer, makes a lot of getters futile. Of course it looks you're reaching a tag variable, but still acts like a method, once it was written (in constructor) and now no longer possible to overwrite.

So, can "readonly" replace protected get-ters?

1
  • 1
    They are two different things - protected getters (methods) can be used (or I will call it accessible) in sub-classes, readonly property cannot be changed after initialization. So I cannot understand why you think one can substitute the other. Feel free to further discuss. Commented Nov 27, 2022 at 13:10

1 Answer 1

1

You're almost there. The readonly modifier doesn't add any visibility, so you still need to declare the property protected:

abstract class Base
{
    readonly protected $thing;

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

class Test1 extends Base
{
    private function needThing()
    {
        ... $this->thing;
    }
}

class Test2 extends Base
{
    private function needThing()
    {
        ... $this->thing;
    }
}

This will then work for your specific use case. The RFC where the feature was proposed used an example of a public getter being replaced by a public readonly property, which is exactly the same principle: the property can now have the visibility that the getter used to have.

It's important to note that this is not a universal replacement for getters though - in the original code, the base class could write to the property as many times as it liked, but the readonly keyword means "write only once". For instance, you might have a counter that is incremented by a particular method in the base class, and want child classes to read it but not write it:

abstract class Base
{
    private int $counter = 0;

    protected function getCounter(): int {
       return $this->counter;
    }

    public function doSomething(): void {
        // ...
        $this->counter++;
        // ...
    }
}

class Test1 extends Base
{
    private function needCounter()
    {
        // ... 
        $counter = $this->getCounter();
        // ...
    }
}

Here, readonly is not useful, because it would forbid the $this->counter++ statement in the base class. There is currently a proposal for "asymmetric visibility", which would cater for this use case - you would be able to say that the variable was "private for writing, but protected for reading". If this passes, the earliest it will be introduced is in PHP 8.3, at the end of 2023.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.