In my abstract class My_Class, I have a method My_Class::foo() that's called from within another method belonging to the class. For example:
abstract class My_Class {
function foo() {
// Stuff.
}
function bar() {
$this->foo();
}
// More methods etc...
}
Now, I'm in the process of extending my abstract class. For example:
class My_Class_Extended extends My_Class {
}
As you'll know, both My_Class::foo() and My_Class::bar() are inherited by My_Class_Extended.
I never want My_Class::foo() to be called outside of My_Class or My_Class_Extended so I know not to make its visibility public. My problem is, I'm unsure whether to make its visibility protected or private.
My question
Considering how I'm calling My_Class::foo() in the above scenario, should it be made protected or private? I'm not sure if the call to My_Class::foo() is coming from the child or parent class.
Thanks in advance.
One-line: protected, because you want your child classes have access
The visibility modifiers work like this:
public: visible from everywhere.
$c = new My_Class_Extended(); $c->thisIsPublic();. This doesn't work with private or protected
protected: visible inside of the class and it's child classes
You can only call these functions inside of a function belonging to a class that derives from your parent class, or the parent class itself.
private: Only visible for the class it's defined in. You cannot call private functions in child classes, nor outside of the class.
The modifiers are ordered inclusively. So a protected is more restrictive than public, and private is more restrictive than protected.
You want protected, because you want to call them inside a child class, but not outside of it.
By the way: In your context, the abstract keyword only ensures that you cannot create an instance from My_Class.
Related
Php manual for the late static bindings states, in the example of static usage in non-static context, that foo() will be copied to B? Is method inheritance copying with scope of the original function being maintained?
<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
}
class C extends A {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //fails
As far as I can say, this is a problem of scope. When a child class does not override a parent's class method and you call said method via the child class, you will be in the parent class's scope and have access to private methods of the parent class.
If you implement a test() method in the child class, you will have that scope when you call it and will not be able to access private methods of the parent class.
I would say that 'copy' is not a fitting term for what's happening because the parent methods are not copied, they are just available in the child class, given the right scope. That is, they don't take the scope of the child class, but keep their own. They are only accessible in the child class if set to protected (or public) or if you call private methods with the parent's scope (as described in your example).
More information from your linke here: Strange behavior when overriding private methods
The official documentation does not explain it explicitly, but I could find this:
Private methods of a parent class are not accessible to a child class. As a result, child classes may reimplement a private method themselves without regard for normal inheritance rules.
So let's say I have classes called parent and child, which will be then used from PHP file called caller.php
class Child extends Parent {
}
class Parent {
public function parentMethod(){
}
}
caller.php
PREVENTED:
$child = new Child();
$child->parentMethod();
ALLOWED:
$parent = new Parent();
$parent->parentMethod();
I want to prevent calling parentMethod like this. But if I created Parent object I want to be able to call the parentMethod. Is there some way that I can use to hide this method from being public in Child class, but still allowing parent object to call this method publicly?
Only solution I have come up with so far is making those methods protected and then creating an other class that would extend parent and then have public method for each function that it needs, but that doesn't sound very smart.
Actually, you should ask yourself: why do you need such restriction? You've defined your method as public - thus, you told PHP that it should be visible everywhere. So to prevent child calls you should use private visibility definition.
There is a way to check if call is made from parent class, like:
class ChildClass extends ParentClass {}
class ParentClass
{
public function parentMethod()
{
if(get_class($this) != __CLASS__)
{
throw new LogicException("Somehow due to business logic you're not allowed to call this from childs");
}
}
}
But I would not recommend to do that. Reasons are:
Readability. Your method is just ordinary public method. Looking to it it's impossible to say either you should use it with child calls or not. Thus, to maintain such code you'll need to check that restriction in code. Now imagine that you have ~50 methods like that. And dozen of classes like that.
Possibly, breaking Law of Demeter. Why should parent class be aware of it's childs when using such limitation?
Finally, it's just unexpected behavior. Looking to definition, anybody will see that you're extending one class by another. Thus, by definition all inherit methods with proper visibility must be inherited. And your logic changes that.
You may think about composition, not inheritance. That may be right way to implement your logic (however, I can't tell that for sure since I don't know whole background)
You can rearrange your code by adding a base parent class for both of your mentioned classes. Like so:
class Base {
public function inheritableMethod1() {}
public function inheritableMethod2() {}
}
class Child extends Base {
}
class Parent extends Base {
public function additionalMethod() {}
}
Move all inheritable methods from the Parent class to the Base, and leave there only those which must not be called on Child (the parentMethod in your example).
The base class optionally might be abstract to prevent instantiating it directly.
Check if Abstract Class suits your needs:
PHP: Class Abstraction
class Child extends Parent {
public function parentMethod(
# Code
}
}
Abstract class Parent {
abstract public function parentMethod();
}
I'd like to develop an abstract class to be extended to fit custom requirements. Most of the methods will be fully implemented in this base class. However, it will rely heavily on the values set in the members, which the child class should define. The reason I'm saying "abstract" class is that I want to force the extenders of the class to define values for the members. Is this possible?
I know I can define methods to be abstract and force extenders to implement those. I'm not sure about members. Furthermore, is this good design practice?
Example:
abstract class foo_bar
{
// I want child class to define these
private $member1 = 0;
private $member2 = 0;
private $member3 = 0;
// Child class and instances can access this
public function foo()
{
return 'foo';
}
// Child class must implement this
abstract function bar();
}
In short: No. There's no such thing as abstract properties in PHP.
You may as well just declare those properties as protected in the abstract class itself so the child inherits them. Even if you'd declare them abstract, there's no guarantee the child implements them with useful values, so it has about the same effect.
Let's say I have 2 classes
class BaseClass {
...
}
class SomeClass extends BaseClass {
}
now I want to create third class, that will only extend SomeClass, but not get anything from BaseClass. Is that even possible?
I'm writing Selenium tests with webdriver and want to check data from Selenium against DB or WebServices, but don't want to load the whole framework, just some of our libraries
You can't. That's not how Inheritance works. A class inheriting from SomeClass will always inherit all it's properties and methods, including those of SomeClass inherited from BaseClass. You can limit access to them through Visibility, but only from private over protected to public, not the other way round, e.g. you can loose visibility, but not tighten it.
See the chapters in the PHP Manual about Inheritance and Visibility:
http://php.net/manual/en/language.oop5.inheritance.php
http://php.net/manual/en/language.oop5.visibility.php
Another option would be to use some sort of Facade around an instance of SomeClass to control the access to properties and methods accessible in SomeClass, e.g. assuming your SomeClass has a method foo() and inherits bar() from BaseClass, you could do
class LimitedAccess
{
private $instance;
public function __construct(SomeClass $someClass)
{
$this->instance = $someClass
}
public function foo()
{
return $this->instance->foo;
}
}
and then you can funnel all access through this Facade effectively preventing access to BaseClass::bar(). Note, that this will not change the inheritance hierarchy in any way. It just controls access.
Think about as Human...
You have mother and she has mother...
You cant be son of your mother without being grandson of your grandmother..
same is at PHP
when Class extends other its AWAYS his child...
You can definitely do that if you put a PROTECTED access modifier on the method in BaseClass that you want to be restricted to be called from the Third class..
I am learning about OO and classes, I have a couple of questions about OO and classes in PHP
As I understand it, a class that extends another class simply means that the class that extends the other class has access to the variables/properties and the functions/methods of the class that it is extending from. Is this correct?
I know that a static method or property are basically the same as a procedural function or variable outside of a class and can be used pretty much anywhere. Is this correct?
Public means any class can access it and Private means only the class that is is encapsulated in or a class that is extended from the owner of can access and use. Is this correct?
1) Yes, that's correct. A child class inherits any protected or public properties and methods of its parent. Anything declared private can not be used.
2) This is true. As long as the class is loaded (this goes well with your autoloading question from before), you can access static methods via the scope resolution operator (::), like this: ClassName::methodName();
3) You have the meaning of public correct, but as I mentioned earlier, private methods can only be used by the class they are declared in.
class parentClass
{
private $x;
public $y;
}
class childClass extends parentClass
{
public function __construct() {
echo $this->x;
}
}
$z = new childClass();
The above code will result in a NOTICE error being triggered, as $x is not accessible by childClass.
Notice: Undefined property:
childClass::$x
If $x was declared protected instead, then childClass would have access. Edit: A property declared as protected is accessible by the class that declares it and by any child classes that extend it, but not to the "outside world" otherwise. It's a nice intermediate between public and private.
For 1. As I understand it, a class that extends another class simply means that the class that extends the other class has access to the variables/properties and the functions/methods of the class that it is extending from. Is this correct?
ANS: That is correct but that is not all. The extending class can also customize the extended class by overriding the method of the extended class. And ofcouse, it can also extend the super class functionality by adding new fields and methods.
For 2. I know that a static method or property are basically the same as a procedural function or variable outside of a class and can be used pretty much anywhere. Is this correct?
ANS: Yes that is correct and as zombat said as long as the class is public and loaded and the property and method is public. In other word, you are using the class as name space of those elements.
For 3. Public means any class can access it and Private means only the class that is is encapsulated in or a class that is extended from the owner of can access and use. Is this correct?
ANS: Think of it as physical properties, public computer (at a library) can be used by everyone and your private computer (supposibly) can only be used by you.
Just to added to Zambat comment.
There's very little need to declare anything private, as a general rule use protected instead.