PHP defining private abstract function/method - php

Went over a thing like this and I don't know
abstract class Foo {
abstract private function test();
}
Is this a nonsense or NOT?
If not please explain why.

if you speak about private range inside you abstract class, no it is not a nonsence
Since an abstract class can contain functionality (as opposed to an interface) it can have private variables or methods.
I will give you this link with a great answer (even it is in java, it is the same with php) Why is there a private access modifier in an abstract class in Java, even though we cannot create an instance of an abstract class?

Abstract methods cannot be private, because by definition they must be implemented by a derived class. If you don't want it to be public, it needs to be protected, which means that it can be seen by derived classes, but nobody else.
The PHP manual on abstract classes shows you examples of using protected in this way.
http://php.net/manual/en/language.oop5.abstract.php

It makes sense if you want to make that method inaccessible further down in the inheritance chain, e.g. grandchildren of that abstract class. For example:
abstract class Foo {
abstract private function test();
}
class FooChild extends Foo {
private function test()
{
// Here you implement the body of the method
}
public function bar()
{
$this->test(); // This will work
// Do something else
}
}
class FooGrandChild extends FooChild {
}
$grandchild = new FooGrandChild();
$grandchild->test(); // This will throw an exception

Related

Inheritance and function calls parent and sub-class

I encountered the following structure:
// parent class
class A
{
public function myFunc1()
{
$this->myFunc2();
}
private function myFunc2()
{
echo "called from class A";
}
}
// sub-class
class B extends A
{
private function myFunc2()
{
echo "called from class B";
}
}
$foo = new B();
$foo->myFunc1();
I expected, since there is no myFunc1() in class B, that the parent-function is called. This seems to be correct.
Now, to play it safe, I var_dump $this in myFunc1() and it shows, that this is an object from type B.
From my understanding, it should call myFunc2() from the Class B, but this isn't happening. It is calling the method from class A.
called from class A
instead of
called from class B
Yes, the functions are private and if I change it to protected, it works as expected. But private implies, that I have access to this function(s), when I'm in the specific context, doesn't it?
Private functions are only available within the class they are defined in, not in sub classes.
This means that your Object has two completely different functions, that happen to have the same name. Object B is aware of having one of them while Object A is only aware of having the other one. They do not interact in any way.
Since these functions are entirely private to the specific class they were defined in, there is no way to override them, or for any other class to call them.
If you need behavior that allows you to override how the class works, you'll have to use protected instead, which is designed specifically to be callable and changeable from extensions (and as such is a completely different beast all-together).
private always belongs to the same class you can't inherit it. That's the reason why myFunc1() calls myFunc2() from class A. If you want to overwrite it you have to change the visibility to protected.

"Class X extends Y (abstract), Y implements Z (interface). "Cannot call abstract method of interface Z"

Here are my PHP abstraction classes. The bottom most class is one of the classes that will extend the abstract class and leave some of the complex calculation logic to the parent implementation.
The point of the interface class (the top most abstraction) is to force those lower implementations have their own static public function id($params=false){ method.
// My top level abstraction, to be implemented only by "MyAbstraction"
interface MyInterface{
static public function id();
}
// My second (lower) level of abstraction, to be extended
// by all child classes. This is an abstraction of just the
// common heavy lifting logic, common methods and properties.
// This class is never instantiated, hence the "abstract" modifier.
// Also, this class doesn't override the id() method. It is left
// for the descendant classes to do.
abstract class MyAbstraction implements MyInterface{
// Some heavy lifting here, including common methods, properties, etc
// ....
// ....
static public function run(){
$this->id = self::id(); // This is failing with fatal error
}
}
// This is one of many "children" that only extend the needed methods/properties
class MyImplementation extends MyAbstraction{
// As you can see, I have implemented the "forced"
// method, coming from the top most interface abstraction
static public function id(){
return 'XXX';
}
}
The end result is that if I call:
$o = new MyImplementation();
$o->run();
I get a fatal error:
Fatal error: Cannot call abstract method MyInterface::id();
Why is MyAbstraction::run() calling the id() method of its parent (interface) instead of the method found in its child (descendant) class?
All methods declared in an interface must be public; this is the nature of an interface. Reference - PHP interface
You are using self::id() in MyAbstraction class, self always refers same class. reference self vs static
you should use static instead of self. Refer below code.
interface MyInterface{
public function id();
}
abstract class MyAbstraction implements MyInterface{
public $id;
// Some heavy lifting here, including common methods, properties, etc
// ....
// ....
public function run(){
$this->id = static::id(); // This is failing with fatal error
}
}
class MyImplementation extends MyAbstraction{
// As you can see, I have implemented the "forced"
// method, coming from the top most interface abstraction
public function id(){
return 'XXX';
}
}
$o = new MyImplementation();
$o->run();
In above code static::id() will call function of class which is in context i.e. MyImplementation class.
This phenomenon known as Late Static Binding
"self" is reference to "MyAbstraction" class (itself). So it try to search MyAbstraction::id(), and got an error.
You shoud use "static" keyword static::id();
You cannot use $this in static method ($this->id).
All of your methods are static, so You do not need instantiate an object.
You can do the same with a static call: MyImplementation::run();
Try to replace your self::id() by static::id().
You use the Late Static Bindings of PHP here.

How to force an implementation of a protected static function

I'm trying to write an abstract class (or interface) which forces the extending class to implement a protected static function.
But this is neither possible with an abstract class nor an interface.
Errors:
static functions should not be abstract
access type for interface members must be omitted
Any ideas how to accomplish that?
UPDATE
The purpose is basically to call the public function statically. This way the class does not need to be instanciated.
It is also not necessary to make _doSpecificStuff() callable from class-external code.
abstract class Foo
{
public static function doStuff()
{
[generic code]
static::_doSpecificStuff();
}
// sth like that would be nice to have:
abstract static protected function _doSpecificStuff();
}
From a theoretical as well as a practical standpoint, there's no real need to declare a static method abstract.
Abstract methods are there to have a child class fill in a blank. That's typically because the parent class (the original abstract class) does some generic operation, but can/must be adapted to certain specific situations and can thus force child classes to implement only this particular variable part in the otherwise generic algorithm. Abstract methods are supposed to be a blank spot within a larger algorithm.
A parent method would call implementations of its abstract methods without knowing or caring who implements them or how they're implemented:
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
Foo doesn't care who or what fills in the blank doSomethingSpecific, it just relies on it being there and its signature, which abstract enforces. The specific object which implements this method or how it implements it is variable. This is important and is at the core of the issue.
Declaring a static method abstract is pretty useless in this scenario. Any static method can just as well be implemented as a non-static method, so there's no use for it here. If the class itself is supposed to call the abstract method as part of a larger generic algorithm as described above, there's no need for a static method.
So the only scenario left for a static method is for a public static method which is callable from anywhere:
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
The thing is, since the abstract class Foo is not itself calling this function but this function is only called from external code, you're not really talking about a fill-in-the-blank method, you're talking about an interface. So, you should be using an interface instead.
But even there, since you have to type the specific class name in your source code, hardcoded, there's little point for an interface as well.
The point of declaring an interface or abstract method signature is that you want to fix the method signature so any code can call that particular method without caring what object it's calling it on in particular. But since you have to hardcode the class name, there's no variability in the object you're calling it on. If you type Baz::bar(), you know exactly what class you're calling what method on. Therefore there's little point in abstracting the interface/signature.
Compare:
interface FooInterface {
public function bar();
}
function baz(FooInterface $foo) {
$foo->bar();
}
The function baz can rely on its argument having a bar() method due to the interface declaration. The specific object that's implementing the method is irrelevant and will vary.
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
The class Foo can rely on it having the doSomethingSpecific method. The specific object that's implementing the method is irrelevant and will vary.
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
What exactly are you relying on or abstracting here? You can be pretty darn sure Baz will have the method bar() every time, because you're only ever calling it on the same hardcoded class. Nothing is variable here.

Alternative model for PHP abstract static class methods

Ok, so I've read lots of posts on here about this, but I think this is a specific and new question.
I want the functionality of what lots of us on here wrongly call an "abstract static method". That is: I want a class that insists classes that extend it implement certain static methods.
It seems there are two roads round the much discussed problem of not allowing abstract static, but both seem inelegant.
Problem
The following generates an error: "PHP Strict Standards: Static function A::fn() should not be abstract".
<?php
abstract class A
{
abstract static public function fn();
}
class B extends A
{
static public function fn()
{
// does something on class vars etc.
}
}
Solution 1: use Interfaces
<?php
interface iA {
static function fn();
}
abstract class A implements iA
{
} // obviously this would have other stuff in it in reality
class B extends A
{
static public function fn()
{
// does something on class vars etc.
}
}
The problem with this is that an interface assumes (dictates) that all the methods be public. So while this achieves the goal of insisting that sub-classes of an abstract class have certain static methods, it can only be used for public methods; there is still no way to ensure subclasses of A implement a protected static method.
Protected static methods are useful when the method works entirely on static data but ought not to be called from 'outside'.
Solution 2: exceptions
abstract class A
{
static public function fn()
{
throw new Exception(get_called_class() . " must implement fn()");
}
}
class B extends A
{
static public function fn()
{
// does something on class vars etc.
}
}
This works at runtime if fn() when called. But it's not useful to have to deal with coding syntax mistakes at runtime. And while this could be a hack for one method, it's a lot more code for each method.
Is there something so wrong with this design that the language rightly forbids it? Seems odd that there are various ways to insist subclasses provide most types of method, but not static ones.
It's because static methods belong to the class where they are defined. A::fn() and B::fn() are two different methods, regardless of the inheritance tree. So it makes little sense to define A::fn() as abstract.
Maybe your methods in question should not be abstract at all? If you want to use any kind of polymorphism, there should be objects involved.
I might be totally wrong, but I have no problem in using
abstract class A
{
abstract static public function fn();
}
class B extends A
{
static public function fn()
{
print 1;
}
}
B::fn();
It produces 1 as an output. I have run your code in here. What version of php do u use ?

How to extend only one parent?

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..

Categories