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

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

Related

Why are functions in cakephp 3.x controllers and tables public but functions in entities protected?

I am using cakephp 3.x
I made this observation. Functions in controllers and tables are declared as public. Functions in entities are declared as protected. Why can't entities functions be declared as public as well?
This sounds like you have no idea when and why you use the visibility scope. See this question "What is the difference between public, private, and protected?" as well.
In fact nothing prevents you from declaring a public method in an entity, try it. Nothing prevents you from using protected and private in other classes as well. But use them where it makes sense architecture wise. Also entities already have public methods. I suggest you to read the chapter about entities in the book, it explains in detail how entities work, what they are and what they're thought for and what you can do with them.
Entities represent data, the data is accessed through the properties or like an array because the object implements ArrayAccess. To access virtual properties (again, read the chapter) the accessors and mutators are used, which are in fact protected. These methods get called when you try to access a non existing property, see the get() method. They're protected because direct access to them is not desired, it would break the way the entities work. Data is thought to be accessed only through the properties or the get() method so that all entities everywhere work the same.
In well written code the visibility scope usually has a reason. But I've seen bad code where people made things private like crazy without reason, which effectively prevents you from altering the objects behaviour by inheriting them. I haven't checked but I'm pretty sure you won't find a private method in the framework because it is thought to be extended.
Bottom line: Analzye the code and get an understanding of why something is protected if you like to know it. It will be for a different reason from case to case.

Should I apply the same practice to PHP access specifiers as I do to Java specifiers?

I'm currently doing a tutorial on PHP and it has me create a class Person which might represent a user on a website.
There are two public fields ($firstname and $lastname) and the tutorial has me access them using $some_person->firstname.
I know in Java we would most likely want to make these fields private and use getters and setters to access them. Should I apply this same practice to PHP?
Yes - PHP5+ supports public/protected/private methods in classes. You don't need to design getters/setters but if the class grows/adds functionality it'll be safer than letting people call the properties directly.
Yes, in general properties should be made protected or private and getters and setters offered. This will allow you to add in type hints in the setter signature or validation in the setter body, which will make it harder for bad data to slip into properties unnoticed. I tend to recommend this approach even if "you don't need it now" - you may do so later.
The argument against public properties in PHP is just the same as it is in Java: it opens up the "black box" of the class to the outside world, and starts to break down the encapsulation that classes are meant to offer in the first place.
Classes are usually meant to be extended, which has a bearing on whether properties should be protected or private. If child classes are trusted (e.g. part of the same codebase) the developer may be happy to allow direct access to the property, in which case it can be protected. However, if the code is intended for release (e.g. as a F/OSS library) then there's an argument for forcing child classes use the getter and setter methods, in which case the properties should be private.

PHP protected java style

I have a functionality that need to be shared by a few classes that manage a common aspect of my software. In Java, i would have all theses classes in the same package and the common functionality would be in a protected method in a helper class.
In PHP, protected method mean that you can only use it in sub-classes so my current solution is to make the method protected and have all the classes needing this method to extend the helper class. The problem with my current solution is the fact than you can't inherit multiple classes so lets say i need to helper classes, im ...
So, is there a way to have a method visibility comparable to java protected in PHP? If not, any cleaner way to solve my problem?
It sounds that you are looking to use traits.
http://php.net/manual/en/language.oop5.traits.php
This would let you define your shared protected method and provide to the classes that require it. I would recommend implementing this with an interface so that you can specify that the method provided by the trait has to be there.
PHP only lets you extend one abstract class however you can implement multiple interfaces.
You could try namespaces (5.3) and reference the utility class instead of extending it. This doesn't quite solve the problem but it does help isolate your class. I try to avoid using private methods.
In PHP 5.4 they added traits which kind of allow a class to extend multiple classes. Schleis has already answered with that.

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.

Correct Implementation of Virtual Functions in PHP?

at my working place (php only) we have a base class for database abstraction. When you want to add a new database table to the base layer, you have to create a subclass of this base class and override some methods to define individual behaviour for using this table. The normal behaviour should stay the same.
Now I have seen many new programmers at our company, who just override the method for the default behaviour. Some are so "nice" to put in all the default behaviour and just add there individual stuff where they like it, others kill themself trying to use the baseclass and their inheritor.
My first thought to solve this problem, was thinking about abstract methods that should be overriden by inheriting classes. But beside other arguments against abstract methods, "abstract" just does not show why the baseclass can't be used by its own and why these function should be overriden.
After some googling around I didn't find a good answer to implementing "real" virtual functions in php (just that there is a virtual function, that nearly kills all hope of a concrete implementation).
So, what would you do with this matter?
In PHP all public and protected functions are "virtual". You can prevent functions from being overriden by prepending the final keyword. (Or by making them private, but this is probably a bad idea).
In the design of the baseclass I would think of behaviors that subclasses would want to affect.
I would for example create empty functions like before_update() and after_insert().
function after_insert() {
// Virtual
}
Which the baseclass will call when an update/insert event occurs.
Maybe an is_valid() function which always returns true in the baseclass, and use the commentblock to describe what the consequences are when a subclass return false.
Hopefully this would give you some inspiration.
You can always use the "final" keyword to prevent some of the classes functions from being overridden if people are using the class in the wrong way.
It sounds to me like they are unable to acheive certain functionality hence overriding the methods. You may need to take a look at the design of your classes.
Without an example of the implementation of your base class, it's hard to give concrete info. But a few things come to mind:
Database abstraction is complex stuff to begin with. I understand that you want to keep it lean, clean and mean, but I think it's pretty darn difficult. You really have to take a thorough look at the specs of different DB engines to see what parts are general and what parts need specialization. Also; are you sure you don't have DB abstraction mixed up with the Table Data Gateway pattern, as you are talking about adding DB tables by extending the base class?
The methods of your current base class might be doing too much and/or are not general enough to begin with, if the extended classes are bending over backwards too keep it clean. Maybe you should break the base class interface methods up in smaller protected methods that are general enough to be reused in the overriding methods of the extended classes? Or vice versa: maybe you should have hooks to overridable methods in your interface methods.
Following from point 2: What's wrong with having an abstract class with some general implemented methods, and let your vanilla class (your base class) and other classes inherit from that?
Lastly, maybe you should just enforce an interface to be implemented, in stead of extending the base class?

Categories