PHP. Is it possible to redeclare non-abstract method as abstract? - php

Key class has a non-abstract method getDescription() (for many purposes).
Key class is extended by (one of) "a child abstract class".
"A child abstract class" is extended by "a concrete class".
I want to force "a concrete class" to implement getDescription() method and try to redeclare it in "a child abstract class" as an abstract method, but fail.
So, is it possible to redeclare non-abstract method as abstract in php?
If not - how to force a concrete method to be implemented?
The key class. I need getDescription as declared in this way for many purposes.
abstract class beverage{
public $description = "Unknown beverage";
public function getDescription(){return $this->description;}
};
The abstract class, overriden getDescription() - but does not work.
abstract class condimentDecorator extends beverage {
//public abstract function getDescription();
};
Concrete class, which MUST reimpliment getDescription.
class milk extends condimentDecorator{
public $beverage;
public function __construct(beverage $beverage){$this->beverage = $beverage;}
public function getDescription(){return $this->beverage->getDescription().", Milk";}
};

is it possible to redeclare non-abstract method as abstract in php?
No, you can't do that in PHP
It seems that you are trying to implement a Decorator pattern.In such case the presented classes chain is over-complicated.
Decorator pattern is dedicated to add(extend) functionality to another class without changing its structure.The following is a classical and more optimal approach of implementing decorators:
abstract class Beverage {
public $description = "Unknown beverage";
public function getDescription(){
return $this->description;
}
}
class CondimentDecorator extends Beverage {
protected $beverage;
public function __construct(Beverage $beverage) {
$this->beverage = $beverage;
}
public function getDescription() {
return "Description:\t" . $this->beverage->getDescription() . " with condiment";
}
};
class Milk extends Beverage {
public function __construct($desc = "") {
$this->description = $desc;
}
}
$milk = new Milk('Milk beverage');
$milk_with_condiment = new CondimentDecorator($milk);
echo $milk_with_condiment->getDescription();
The output:
Description: Milk beverage with condiment

I think the main problem is how you're implementing this.
If you've an class that already implements a method all it's children will by default implement it.
So lets say you've the following:
Class A {
public function niceFunction() {return "some awesome return with potato"; }
}
Class B extends A{
//it already has niceFunction
}
Class Avocado extends B {
// it also already has NiceFunction
}
So what you want to do is overwrite the default function.
I think you should take a time and re-think if the structure is correct.
The condimentDecorator couldn't be a interface?
Editd:
My suggestion would be do something Like this:
Interface Descritible()
{
public function getDescription();
}
class beverage implements Descritible{
//do the stuff you need to do
// It must have getDescription() cuz it implements Descritible
}
abstract class A implements Descritible{}
class Avocado extends A {
//It'll not have a default implementation of getDescription
//so it'll have to implement it.
}
So then the Class avocado will need to implements getDescription as Beverage would've as well, and you should be conflict free.

Related

Class Circular Dependency

I've seen the following snippet of PHP code, declaring some interfaces, abstract classes and concrete classes:
public interface MyInterface
{
public function method1() : MyAbstractClass;
}
abstract class MyAbstractClass implements MyInterface
{
protected $myVar = 1;
}
public class MyClass1 extends MyAbstractClass
{
function method1(): MyAbstractClass
{
return new MyClass1();
}
}
public class MyClass2 extends MyAbstractClass
{
function method1(): MyAbstractClass
{
return new MyClass2();
}
}
Some commentators argued that there is a circular dependency, and therefore, method1 should return MyInterface instead of MyAbstractClass.
would that be the case?
I'd post this as a comment, but it's a long read.
I suppose neither is "wrong" per-se. But what seems "right" would be something like this:
public interface MyInterface
{
public function method1() : self;
}
abstract class MyAbstractClass implements MyInterface
{
protected $myVar = 1;
}
public class MyClass1 extends MyAbstractClass
{
function method1(): self // yes, you can return self
{
return $this;
}
}
public class MyClass2 extends MyAbstractClass
{
function method1(): self
{
return $this;
}
}
The reasoning for return self in the interface is that a class who implements that interface and always return $this will always return...well...itself.
If you were to return MyAbstractClass in the interface, that would make the interface itself redundant since it can only be implemented by that Abstract Class, which completely defeats the purpose of even having an interface.
method1 should return self or the class in which it currently resides. You can of course return the parent class since by inheritance the return type is correct.
You can also return the interface, which is also perfectly fine. In fact, to some degree it seems "more better" or "more correct", but ultimately, it boils down to return self.
My 2 cents. The latter statement regarding method1 is open for interpretation, but ultimately the first one, regarding the interface, should definitely not be. An interface should never have a return type of the class that implements it.
It sucks that PHP doesn't yet have static as a valid return type. That would solve the problem by definition.
See this question also
PHP 7 interfaces, return type hinting and self
The accepted answer makes a fair point.

Is there a way for abstract protected static method in PHP for later inheritance?

I've already read Why does PHP 5.2+ disallow abstract static class methods? and How to force an implementation of a protected static function - the second is very similar to my case - but I am still without answer. Basically, I want to assure, that every child of my abstract class has implementation of protected static method, without implementing it as this has no meaning and because of lack of key informations there. Also, it must be static (because caller method is static and it has no context) and protected (so I cannot use interface, and I do not want anyone to call it directly), and it will be called by late static binding. Any ideas?
Dummy code below to illuminate my case:
abstract class BaseClass {
public static function foo() {
// some common stuff
static::bar();
// rest of common stuff
}
public function whoooaaa($condition) {
if ($condition) {
AClass::foo();
} else {
BClass::foo();
}
}
}
class AClass extends BaseClass {
protected static function bar() {
// do something
}
}
class BClass extends BaseClass {
protected static function bar() {
// do something else
}
}
// end somewhere else in my code, two constructions, both used:
AClass::foo();
// ....
$baseClassInheritedInstance->whoooaaa($variableCondition);
My only solution, ugly one, is to implement dummy protected static method in base class and throw a generic exception, so that it must be implemented by inheritance.
You can add a static factory that will fill context for casual objects.
class Factory() {
public static getObject($condition) {
$object = $condition ? new A() : new B();
// you can fill context here and/or use singleton/cache
return $object;
}
}
abstract class Base {
abstract function concreteMethod();
}
class A extends Base {...}
class B extends Base {...}

PHP abstract class does not affect the child of its child

I have an abstract class that declares the methods required to its children. It also has a construstor that its children inherits. How can I make the abstract class affect the children of the classes that extends it. To further clarify my question, here is my case:
The Abstract Class (abstract.php):
<?php
include_once 'database.php';
include_once 'validation.php';
abstract class DataOperations extends DatabaseConnection {
//The error string shared by all children of DataOperations
//This will be the message to be displayed in case validation failure
public $validator;
public $err_valid_string;
/**
* The DataOperations' constructor ensures that all of its children can perform database operation
* by automatically starting it for them. In case a child overrides this constructor, this child
* must explicitly start the connection to prevent fatal errors. Also, $validator must be re-instantiated
*/
public function __construct() {
$this->startDBConnection();
$this->validator = new InputValidator();
}
public function __destruct() {
}
abstract public function validateData();
abstract public function loadRecord($key, $cascade);
abstract public function saveRecord();
abstract public function updateRecord();
abstract public function deleteRecord();
}
?>
Now, here is the child object that extends the DataOperations abstract class
class Guest extends DataOperations {
//some properties here
public function validateData() {
//implementation
}
public function newRecord(implementation) {
//implementation
}
public function loadRecord($key, $cascade){
//implementation
}
public function saveRecord() {
//implementation
}
public function updateRecord() {
//implementation
}
public function deleteRecord() {
//implementation
}
}
?>
And here is another class, which is a child of Guest
class Booking extends Guest {
//some properties here
public function validateData() {
//implementation
}
public function newRecord(implementation) {
//implementation
}
public function loadRecord($key, $cascade){
//implementation
}
public function saveRecord() {
//implementation
}
public function updateRecord() {
//implementation
}
public function deleteRecord() {
//implementation
}
}
?>
The problem is, if I remove a method in Booking, say deleteRecord(), PHP won't throw an error because I think abstract class doesn't affect its 'grandchildren'. How can I fix this? I thought of using interfaces but my system already has 11 classes that depends to some methods of the abstract class. It will require intensive refactoring.
As you himself stated interface is best suited solution. Like
include_once 'database.php';
include_once 'validation.php';
interface DbInterface {
abstract public function validateData();
abstract public function loadRecord($key, $cascade);
abstract public function saveRecord();
abstract public function updateRecord();
abstract public function deleteRecord();
}
class DataOperations extends DatabaseConnection {
//The error string shared by all children of DataOperations
//This will be the message to be displayed in case validation failure
public $validator;
public $err_valid_string;
/**
* The DataOperations' constructor ensures that all of its children can perform database operation
* by automatically starting it for them. In case a child overrides this constructor, this child
* must explicitly start the connection to prevent fatal errors. Also, $validator must be re-instantiated
*/
public function __construct() {
$this->startDBConnection();
$this->validator = new InputValidator();
}
public function __destruct() {
}
}
class Guest extends DataOperations implements DbInterface {
- - -
}
class Booking extends Guest implements DbInterface {
- - -
}
First as you see I removed abstract from parent class as I assuming only those methods are abstract. Second as per your problem of 11 classes depend on Abstract class, I would say As you only remove abstract methods, Class implementing abstract methods now should implement interface. It is one time needed task. While classes using other normal methods of abstract class work like previous.
The best and cleanest way would be to have your "BOOKING" class extend the "DATAOPERATIONS" class, instead of GUEST, because looks like you don't have any extra methods in the BOOKING class. other wise make and interface and implement it. That is not the preferred way but you would have to give more info your situation.
To be clear, re-declaring a method in a child class will overwrite the parent class's implementation of that method when called from the child class, while not affecting any additional functionality provided by extending the parent class:
class a
{
function hello()
{
echo "Hello";
}
function goodbye()
{
echo "Goodbye";
}
}
/**
* class b overwrites class a's implementation of method goodbye but will retain
* it's definition for method hello
*/
class b extends a
{
function goodbye()
{
echo "See ya!";
}
}
$object = new b();
$object->hello(); // Hello
$object->goodbye();// See ya!
It appears that you want to implement a consistent interface across multiple class definitions. If this is the case, you will likely want to explore using PHP's interfaces.
These allow you to specify the methods that must exist in your class definition along with their set of arguments (collectively known as the signature). Your class definitions will implement an interface and if your definition does not meet the interface implementation specification, a fatal error will be thrown.
From the PHP manual:
// Declare the interface 'iTemplate'
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}
// Implement the interface
// This will work
class Template implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}
return $template;
}
// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
}
You can find more information about interface in the PHP manual:
http://us2.php.net/interface
Finally, it looks like you are hoping to define a common constructor for the child classes. Your child classes can both extend the DataOperations class while implementing a separate interface:
class Guest extends DataOperations implements DatabaseWriter
...

Overriding methods in PHP?

In other OO languages like Java we can override a function, possible using keywords/annotations like implements, #override etc.
Is there a way to do so in PHP? I mean, for example:
class myClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
I want user to implement their own myClass::reImplementThis() method.
How can I do that in PHP? If it is possible, can I make it optional?
I mean, if the user is not implementing the method, can I specify a default method or can I identify that the method is not defined (can I do this using method_exists)?
<?php
abstract class Test
{
abstract protected function test();
protected function anotherTest() {
}
}
class TestTest extends Test
{
protected function test() {
}
}
$test = new TestTest();
?>
This way the class TestTest must override the function test.
Yes, there is. You have the option to override a method by extending the class and defining a method with the same name, function signature and access specifier (either public or protected) it had in the base class. The method should not be declared abstract in the base class or you will be required to implement it in the derived class. In you example it would look something like this:
class MyClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
class MyDerivedClass extends MyClass {
public static function reImplmentThis() { //the method you want to call
}
}
If the user does not overrides it, MyDerivedClass will still have a reImplmentThis() method, the one inherited from MyClass.
That said, you need to be very careful when invoking extended static methods from your derived class to stay out of trouble. I encourage you to refactor your code to extend instance methods unless you have a very specific need to extend static classes. And if you decide there is no better way than extending static classes please be sure to understand Late Static Binding pretty well.
Yes, its possible to check if the method is implemented or not and get a whole lot more of information about a class using PHP Reflection.
This touches on several OOP subjects.
First, simply overriding an method declared in a parent class is as simple as re-declaring the method in an inheriting class.
E.g:
class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
}
class Tommy extends Person {
public function greet(string $whom = "everyone") {
echo "Howdy $whom! How are you?";
}
}
$a = new Tommy();
$a->greet('World');
// outputs:
// Howdy World! How are you?
If on the overriding method you wan to reuse the logic of the overriden one, it's just a matter of calling the parent's method from the extending class::
class Tommy
{
public function greet(string $whom)
{
// now with more emphasis!!!
echo parent::greet(strtoupper($whom)) . "!!!!";
}
}
Now Tommy::greet() calls Person::greet(), but modifies the result before returning it.
One thing to note is that overriding methods have to be compatible with the overriden one: the method visibility can't be more restrictive than the original one (it's OK to increase visibility), and the number and type of required arguments can't conflict with the original delcaration.
This works, because the type of the arguments does not clash with the original, and we have less required arguments than on the parent:
class Leo extends Person {
public function greet(string $whom = "gorgeous", string $greet = "Whatsup" ) {
echo "$greet $whom. How are you?";
}
}
But this doesn't, since there are additional required arguments. This would make impossible to switch the original class for this one transparently, and thus would throw a Warning:
class BadBob extends Person {
public function greet(string $whom, string $greet ) {
echo "$greet $whom. How are you?";
}
}
Additionally, you mention in your question that "this method should be overriden by the user". If you require client classes to actually implement the method, you have a couple of options:
Abstract classes & methods
These are methods where the implementation is left empty, and that extending classes have to implement to be valid. In we changed our original class Person to:
abstract class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
public abstract function hide();
}
Since now the class contains an abstract method, it needs to be declared as an abstract class as well.
Now it is not possible to instantiate Person directly, you can only extend it in other classes.
Now all our existing Person extending classes would be wrong, and trying to execute the previous code would throw a fatal error.
An example of a valid class extending Person now would be:
class Archie extends Person {
public function hide() {
echo "Hides behind a bush";
}
}
Any class that extends Person must declare a public hide() method.
Interfaces
Finally, you mention interfaces. Interfaces are contracts that implementing classes have to fulfill. They declare a group of public methods without an implementation body.
E.g.:
interface Policeman {
public function arrest(Person $person) : bool;
public function help($what): bool;
}
Now we could have class that extended Person and implemented Policeman:
class Jane extends Person implements Policeman {
public function hide() {
echo "Jane hides in her patrol-car";
}
public function arrest(Person $person): bool{
// implement arrest method
return false;
}
public function shoot($what): bool {
// implements shoot() method
return false;
}
}
Importantly, while it's possible to extend only one class (there is no multiple inheritance in PHP), it is possible to implement multiple interfaces, and the requirements for each of those have to be fulfilled for the class to be valid.

How to declare abstract method in non-abstract class in PHP?

class absclass {
abstract public function fuc();
}
reports:
PHP Fatal error: Class absclass
contains 1 abstract method and must
therefore be declared abstract or
implement the remaining methods
(absclass::fuc)
I want to know what it means by implement the remaining methods,how?
See the chapter on Class Abstraction in the PHP manual:
PHP 5 introduces abstract classes and methods. Classes defined as abstract may not be instantiated, and any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method's signature - they cannot define the implementation.
It means you either have to
abstract class absclass { // mark the entire class as abstract
abstract public function fuc();
}
or
class absclass {
public function fuc() { // implement the method body
// which means it won't be abstract anymore
};
}
I presume that remaining methods actually refers to the abstract methods you're trying to define (in this case, fuc()), since the non-abstract methods that might exist are okay anyway. It's probably an error message that could use a more precise wording: where it says remaining it could have said abstract.
The fix is pretty straightforward (that part of the error message is fine): you need to change this:
abstract public function fuc();
... into a proper implementation:
public function fuc(){
// Code comes here
}
... or, alternatively and depending your needs, make the whole class abstract:
abstract class absclass {
abstract public function fuc();
}
An abstract class cannot be directly instantiated, but it can contain both abstract and non-abstract methods.
If you extend an abstract class, you have to either implement all its abstract functions, or make the subclass abstract.
You cannot override a regular method and make it abstract, but you must (eventually) override all abstract methods and make them non-abstract.
<?php
abstract class Dog {
private $name = null;
private $gender = null;
public function __construct($name, $gender) {
$this->name = $name;
$this->gender = $gender;
}
public function getName() {return $this->name;}
public function setName($name) {$this->name = $name;}
public function getGender() {return $this->gender;}
public function setGender($gender) {$this->gender = $gender;}
abstract public function bark();
}
// non-abstract class inheritting from an abstract class - this one has to implement all inherited abstract methods.
class Daschund extends Dog {
public function bark() {
print "bowowwaoar" . PHP_EOL;
}
}
// this class causes a compilation error, because it fails to implement bark().
class BadDog extends Dog {
// boom! where's bark() ?
}
// this one succeeds in compiling,
// it's passing the buck of implementing it's inheritted abstract methods on to sub classes.
abstract class PassTheBuckDog extends Dog {
// no boom. only non-abstract subclasses have to bark().
}
$dog = new Daschund('Fred', 'male');
$dog->setGender('female');
print "name: " . $dog->getName() . PHP_EOL;
print "gender: ". $dog->getGender() . PHP_EOL;
$dog->bark();
?>
That program bombs with:
PHP Fatal error: Class BadDog
contains 1 abstract method and must
therefore be declared abstract or
implement the remaining methods
(Dog::bark)
If you comment out the BadDog class, then the output is:
name: Fred
gender: female
bowowwaoar
If you try to instantiate a Dog or a PassTheBuckDog directly, like this:
$wrong = new Dog('somma','it');
$bad = new PassTheBuckDog('phamous','monster');
..it bombs with:
PHP Fatal error: Cannot instantiate
abstract class Dog
or (if you comment out the $wrong line)
PHP Fatal error: Cannot instantiate
abstract class PassTheBuckDog
You can, however, call a static function of an abstract class:
abstract class Dog {
..
public static function getBarker($classname, $name, $gender) {
return new $classname($name, $gender);
}
..
}
..
$other_dog = Dog::getBarker('Daschund', 'Wilma', 'female');
$other_dog->bark();
That works just fine.
You're being slightly led astray by this error message. In this case, since it is within this class that fuc is being defined, it wouldn't really make sense to implement it in this class. What the error is trying to tell you is that a non-abstract class cannot have abstract methods. As soon as you put an abstract method in the definition of a class, you must also mark the class itself as abstract.
Abstract keywords are used to label classes or methods as patterns. It's similar to interfaces but can contain variables and implementations of methods.
There are a lot of misunderstandings concerning abstract classes. Here is an example of an abstract Dog class. If a developer wants to create some basic Dog class for other developers or for himself to extend he declares the class as abstract. You can't instantiate the Dog class directly (nobody can), but you can extend Dog by your own class. SmartDog extends Dog etc.
All methods that are declared to be abstract by the Dog class must be implemented manually in each class that extends Dog.
For example, the abstract class Dog has an abstract method Dog::Bark(). But all Dogs bark differently. So in each Dog-subclasses you must describe HOW that dog barks concretely, so you must define eg SmartDog::Bark().
It means that the proper of an abstract class is having at least one abstract method. So your class has either to implement the method (non abstract), or to be declared abstract.
I wanted to use an abstract method within a non-abstract class (normal class?) and found that I could wrap the method's contents in an 'if' statement with get_parent_class() like so:
if (get_parent_class($this) !== false) {
Or, in action (tested in a file on cmd line: php -f "abstract_method_normal_class_test.php"):
<?php
class dad {
function dad() {
if (get_parent_class($this) !== false) {
// implements some logic
echo "I'm " , get_class($this) , "\n";
} else {
echo "I'm " , get_class($this) , "\n";
}
}
}
class child extends dad {
function child() {
parent::dad();
}
}
$foo = new dad();
$bar = new child();
?>
Output:
I'm dad
I'm child
PHP get_parent_class() Documentation

Categories