Visibility of Protected/Private Properties from Other Instances of Same Class - php

The basic rules of inheritance and visibility go as follows:
Accessing private members from within a class is OK.
Accessing private members from a subclass is not OK.
Accessing private members from a superclass is not OK.
Accessing protected members from instances of a class is OK.
Accessing protected members from instances of a subclass is OK.
Accessing protected members from a superclass is not OK.
Somewhat less obvious are the rules for accessing these properties from another instance of the same class, though it is spelled out clearly in the documentation:
Accessing private members from another instance of the same class is OK.
Accessing protected members from another instance of the same class is OK.
This happens because the object has access to the class spec. It seems to be due to a quirk of implementation in the language, albeit one that we can rely on. What I'm curious about is the rules of visibility from other object instances both up and down the inheritance chain. What I expect is:
Accessing private members from another instance of a class is OK.
Accessing private members from another instance of a subclass is not OK.
Accessing private members from another instance of a superclass is not OK.
Accessing protected members from another instance of a class is OK.
Accessing protected members from another instance of a subclass is OK.
Accessing protected members from another instance of a superclass is not OK.
Is this right?

Yes, it's right.
The visibility rules are based only on classes, instances have no impact. So if a class has access to a particular member in the same instance, it also has access to that member in other instances of that class.
It's not a quirk, it's a deliberate design choice, similar to many other OO languages (I think the rules are essentially the same in C++, for instance). Once you grant that a class method is allowed to know about the implementation details of that class or some related class, it doesn't matter whether the instance it's dealing with is the one it was called on or some other instance of the class.

Not entirely. It's right that the rules are only based on classes, and it does not matter if it is the same instance or another instance and that was basically your question.
However, you made a mistake about protected in general. From the documentation:
Members declared protected can be accessed only within the class itself and by inherited and parent classes
(highlight added)
So, the following statements are wrong:
Accessing protected members from a superclass is not OK.
Accessing protected members from another instance of a superclass is not OK.

Related

Smarty and objects private properties

Smarty allows to access object properties using this syntax in templates:
{$object->property}
But (If I understood this correctly) this is possible only if property visibility is public, otherwise it seems that Smarty won't be able to access it.
In Java I'm used to create objects that have private properties, and I usually read/write these properties in business logic using getters and setters. But, even if I create an object with a private property, I'm able to access it in a jsp using expression language:
${object.property}
This won't happen in Smarty templates, since private properties cannot be accessed this way. So I would have to use a syntax like:
{$object->getProperty()}
Why is that? Why doesn't Smarty get round the problem as jsp EL does?
Reading and writing to private members of object from the outside violates OOP encapsulation principle. If you mark a member of class as private, you expect that no one except the code in the class (or friend functions) can access it.
Keeping as few public members as possible reduces dependencies between different code modules, making your application more flexible. If you can access private member of, let's say your model, your template must know internal implementation of the model. Making changes to your model will cost you a lot of time, because you would need to change your templates as well.
If you have getter and setter of your private member, you are free to change it as you like, template will know nothing.

Restricting the constructor-access to certain classes

Let's say I want to restrict the access to the constructor of a public class, so that only certain classes may create an instance of it, but all classes are able to use the instance.
In Java, I know two ways to archive this:
Make a public static inner class with a private constructor and instantiate it in the outer class.
Make the classes constructor package-private (restricts access to all classes in the same package).
In PHP however, there are no inner classes and the namespaces (which are close to packages) have no own access-modifier (ergo no package-private).
So, how can I protect the access to the classes constructor?

Class method naming issues - conflicts with extended class?

This is less of an issue, and more of a best practice question - I know these are subject to opinion, but I'm sure there must be a standard convention for this particular problem.
Let's say I've got two classes, Account and Associate.
Account contains several methods which are useful to Associate, and so naturally I'd extend the Account class to Associate.
However, an issue of course arises when I have two methods with the same name e.g. create().
So far to counteract this instead of extending the parent class, I've been instantiating it as a variable in the child classes __construct() method, and then calling methods through that, e.g. $this->Account->create();.
Is there another way, e.g. a norm for using an extended classes methods while still having a method of the same name in the child class?
Any answers would be greatly appreciated!
Account contains several methods which are useful to Associate, and so naturally I'd extend the Account class to Associate.
No, this is not naturally, you are misusing inheritance. Or would you say that an associate is an account? If it has an account, use composition. If not, but the account class has methods that are useful for the associate class, they probably shouldn't be in the account class at all. Extract them to one or more other classes which can be used by both, Account and Associate.
The child class method will be called using $this if you are within the child class methods. If you want the parent method though, you'd call parent::create(); from within the child method.
But that is if you absolutely need to extend the Account class, which sounds unnecessary. If the "Account" class has public methods then you don't need to extend it, you can just call them after instantiating the class:
$account = new Account();
$account->create();
Or, if it is a public static method:
$creation = Account::create();

Why does PHP allow protected and private methods to be made public via an override in subclasses?

From some brief fiddling about, I find I get an error when overriding superclass methods in a subclass when I do the following:
Override a protected superclass method with a private subclass method
Override a public superclass method with a protected or private subclass method
However, If I do it in the other direction, no error is thrown:
Overriding a private superclass method with a protected or public subclass method
Overriding a protected superclass method with a public subclass method
This seems counter intuitive to me - I was expecting it to work the other way around in order to enforce information hiding and encapsulation. This appears to allow poor design by allowing internals to be exposed in a way that may break other methods and I can't see a case when this would be a good idea. Why has it been implemented this way and what have I missed?
Also, is this standard practice in other programming languages?
What you call "enforce information hiding" is something, that may break subclasses, because suddenly properties and methods may disappear. You cannot break things by loosing restrictions this way.
With private is a bit different: In this case the property/method does not exists from the child class' point of view. Thus there is no reason, why a subclass may not introduce a property with that name, because it will be a different property.
You are right, that this may lead to poor design, but you can always build an application with poor design.
You can't decrease the visibility of class members, only increase them.
Imagine a class A which has a public method, and a subclass B would make it private. B could be treated as a type A, for which it is assumed that it has that public method.
If a superclass exposes a method publicly, then all its subclasses must also expose the same method (or an overridden version), therefore reducing the accessibility of a method is a subclass is illegal in PHP (and pretty much every class-based OO language).
The opposite is not true, so increasing the accessibility of methods in subclasses is perfectly fine.
If you think expossing a private/protected method in a subclass represents a problem, just make the method final.
See it this way: by NOT making a method final, you are allowing any subclass to overriding it at will; this obviously includes increasing its visibility.

how come in php superclasses can access protected methods of their subclasses?

I just noticed this behavior today - weird, I'm pretty sure in java a you can only access protected methods upstream on the inheritance chain since going the other way violates encapsulation.
Was there a reason for this behavior in the language?
I've found it useful when one method defined in the parent only needs a small part of its functionality to change based on the extension class type. You can call an abstract method from within the parent, and it's functionality changes as needed with the definition of that method in the child classes.
I would also add that sibling classes can also access each other's protected properties and methods, as long as they are declared in the parent class (this can be abstract or not).
This is allowable in Java as well. This is probably allowed in Java however, since protected is also considered to be package level scope and not just relegated to access within the inheritance chain.
protected != private

Categories