Can PHP static methods legally have a visibility of protected or private?
Asked Answered
I

2

14

I realize that it's possible to define a static class method as private and protected in PHP. This allows for an instantiated class, or public static method to access it's own private/protected static methods.

protected static function jumpOver  ()

However I'm not sure if this is legal in the sense of OOP design. I can't find any real info stating it's ok to do this. I'm worried PHP may "patch" this in future versions if this is not a valid and break my scripts.

Inconvertible answered 26/7, 2010 at 16:11 Comment(1)
protected static function is legit, it can be used as helper method for other static methods.Chase
V
10

It is. Static methods are usually nothing more than helper methods that have code you possibly don't want to be public.

The other common object-oriented languages I can think of have it too (C++, Java, C#). I really don't think they're ever going to remove that feature.

Besides, the guys at PHP are slow at breaking existing features, so I wouldn't worry too much about it.

Verbid answered 26/7, 2010 at 16:15 Comment(4)
uhm...isn't final the keyword you want to use to protect your code?Quartana
@dierre: final protects from overriding/inheritance, but it doesn't protect access.Verbid
oh, ok. Sorry I thought by saying "have code you possibly don't want to be public" was referred to the possibility of override/inherit it.Quartana
Those other languages have it too for the same good reason: as @Chase points out, it can be used to protect those methods used by other public static methods which you don't want to expose.Mesopause
M
0

As Linus suggests to us in his wisdom, let's look at some code.

Say, you have your "static" class (not a thing):

class MyClass
{
    public static function doThing(): void
    {
        // Do something
    }
}

Now, say you wanna add another method, which shares some logic with the first one:

class MyClass
{
    public static function doThing(): void
    {
        // Do something
        // Then, do this particular thing
    }

    public static function doOtherThing(): void
    {
        // Do something else
        // Then, do the same particular thing
    }
}

Makes sense to extract that same particular thing that both doThing() and doOtherThing() to a method of its own, right?

class MyClass
{
    public static function doThing(): void
    {
        // Do something
        static::doParticularThing();
    }

    public static function doOtherThing(): void
    {
        // Do something else
        static::doParticularThing();
    }

    public static function doParticularThing(): void
    {
        // Some more generic or repetitive logic
    }
}

Great! Now consumers of MyClass can also start using doParticularThing(). Like with any other public API, this can lead to a situation where you remove that method because no other logic of yours depends on it anymore, and break all consummers of doParticularThing(). They come and create issues in your tracker. Let's say you don't want that:

class MyClass
{
    public static function doThing(): void
    {
        // Do something
        static::doParticularThing();
    }

    public static function doOtherThing(): void
    {
        // Do something else
        static::doParticularThing();
    }

    protected static function doParticularThing(): void
    {
        // Some more generic or repetitive logic
    }
}

Now you have a class that other code can use to doThing() and to doOtherThing(), but they are safe from doParticularThing() that you might change or remove later. This is good API design, and your consumers will thank you if you use this approach correctly.

Mesopause answered 19/8, 2023 at 18:2 Comment(2)
Credit also to @d.raev, who mentioned it first in a comment. But that comment is not very visible, and I feel this point of view needs a representation that can be accepted as an answer.Mesopause
Also, as a bonus in my example, consumers of MyClass can change the way doParticularThing() and no other method works, if they need to. That's partly because the protected members are indeed protected and not private, and nothing is final. But also, because doParticularThing() is invoked with static and not self: this ensures that the inherited doThing() and doOtherThing() invoke the overridden method, and not the one of MyClass.Mesopause

© 2022 - 2024 — McMap. All rights reserved.