Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

thelazzyriveryogi's avatar

Learning public, private, protected scopes

I have this problem where, while I understand the basic idea of public, protected, and private functions and properties I find that I almost always use public just because I never run into any trouble with it. Every so often I try and branch out and use the others (in times when I choose not when some tutorial or pattern seems to require it) and often I have more trouble getting it to work how I expect.

So my question is kind of abstract but I am trying to understand how to learn this in such a way that I can use it. Maybe with some concrete examples of how a public method or property can burn you? Maybe some reasons why a private or protected method/property will make something not work? A way to practice using protected and private, from within the scope of a project hopefully and not just some simple vanilla thing?

It seems to me like an interface a protected or private is simply away to protect yourself from being stupid in the future, but I don't yet see with regards to these how and when its really valuable, as opposed to just not using something when out of context... which I may or may not be understanding because as I said the few times I experimented with private or protected I didnt quite get it working how I wanted...

0 likes
6 replies
andonovn's avatar

The very basic example and possibly the most used in real-life app is a protected/private property with a setter method. And the benefit is obvious - you can protect that property from the setter, thus making sure it will always contain the type of variable you expect it to have. Example:

class Subscribe {
    /** App\User **/
    protected $user;

    public function setUser(\App\User $user) : self
    {
        $this->user = $user;

        return $this;
    }

    // in projects using php5 you may see things like this
    // same idea but we add additional if because we can't type-hint a string
    protected $name;

    public function setName($name)
    {
        if (!is_string($name)) {
            throw new Exception('Name must be string');
        }

        $this->name = $name;
    }
}

A real-life example for methods is from Controller:

public function show()
{
    // this is public, so we expect it to be associated with some route
}

private function upload()
{
    // this is private, so we know we only use it from the current controller (by the time we see "private" or "protected" we are already know that this is not associated with any route but is a helper method)
}

Most of the time you will use public tho, but don't make public things that you know you would never use outside of the class.

Hopefully that helped you a little bit as I can't really explain where and how to encapsulate your data. Most probably some people will advise you to read more about OOP and encapsulation but I think most people are getting better at this just by reading and writing more code.

1 like
Snapey's avatar

I think its a lot less relevant if only you manage your own code.

If you were writing a package though, you might want to be clearer what attributes and functions are for the internal use of your class and which ones should be interacted with.

1 like
Nash's avatar

Perhaps a little off topic, but I used to work a lot with a framework called CodeIgniter. It had this thing called "magic routes" where your routes would automatically point to the public methods in your controllers, e.g.

class Posts {
    public function create()
    {

    }
}

would automatically be accessible through /posts/create.

This "danger" doesn't apply to Laravel where we specify our routes manually, but it gave you this mindset that if you didn't want something to be directly accessible, called or touched, then it should be private or protected rather than public, and I think that idea still holds up pretty well.

thelazzyriveryogi's avatar

interesting points/examples.

i was kind of thinking what snapey said. If I know how my code works its not such a big deal but if other people get involved maybe its wiser to reduce the scope of certain methods.

I get the idea above about the private method in the controller. Although it seems to me that i wouldnt really call it from anywhere else anyway, it makes sense that it makes it visible so that when I read the controllers source I can recognize that its a helper method instead of a route.

If anyone cares to expand on how the protected $user above with the setter method could threaten my code if public I would love to hear. How and or why would someone set the user from outside the class, or why is the setter public and the property private. This ensures the method can be called from elsewhere, but the property not set directly from elsewhere? This ensures that the setter is called and the type of the user property is an instance of App\User... I guess this makes sense but back to the original question, how or why might someone try to set the user from elsewhere, and if they did arent they just gonna break the code? if thats the case and the code breaks, if you have tests the coder will see right away it is broken and be tasked with figuring out he set the wrong kind of user.

which leads me to another point, if the code is thoroughly tested then is this method and property scoping even less important even if there are multiple people working on the code? I guess that even then it will be a benefit to save those other coders time if they can see at a glance the scope of properties and methods as the original code intended.

andonovn's avatar

@thelazzyriveryogi In regards to the user setter: yes, you got it - by keeping the property private/protected but the setter public you are making sure that the property will always have a User instance.

You are kinda right that the code will fail and the developer will see it but that's not guaranteed. Let's say that $this->user->save() is used inside an if statement. A developer makes a mistake and assign the integer value 0 to the $user dynamically (so, imagine it $subscribe->user = foo() where foo() is unexpectedly returning 0 for some reason). Now the mistake is made but he is not hitting that condition when he is interacting with the code so he thinks everything is fine and continue with his next task. And in production someone will eventually hit that if condition and you got a bug that could of been avoided if the developers were encapsulating their code. I know this example may sound too "unreal" but these things happen. And I am sure there are better examples than this but that's what's popped up in my mind now.

As of tests - sure, if you covered absolutely everything with tests (which happens really rarely), you will know that your tests will fail and you will find your mistake. But imagine you forgot to run your tests after that mistake?

And generally, if encapsulation is one of the 4 major OOP principles, maybe there are good reasons for this. And I don't see why anyone wouldn't want to apply it in his/her code.

Please or to participate in this conversation.