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.
Related
I am trying to extend a package with my own functional ability. But the package code has type hints in the function calls, to other classes that are part of the package.
I am just looking for a way to modify the code.
More details about what I'm trying to do at
https://laracasts.com/discuss/channels/general-discussion/type-hint-hell
I have tried changing the code to use interfaces and abstracts, but i cant seem to prevent the "Declaration of class .... must be compatible with"error.
This is what i'm trying to do in a nutshell.
The package has this type of setup.
class ClassA {}
class ClassB {
public function makeClassA(ClassA $classA) : ClassA
{
return $classA;
}
}
This is what I am trying to do.
class ClassANew {}
class ClassC extends ClassB {
public function makeClassA(ClassANew $classA) : ClassANew
{
return $classA;
}
}
I get the following error,
"PHP Fatal error: Declaration of ClassC::makeClassA(ClassANew $classA): ClassANew must be compatible with ClassB::makeClassA(ClassA $classA): ClassA"
I know I could just fork the code and strip out the locked classA from ClassB, but I was trying not to do that.
If i was going to fork the code, I looked at how to maintain the premise of the original code. So, I tried changing the ClassA references in ClassB to a ClassAInterface, but I get the same error.
Is what I'm trying to do possible?
No, this is not possible to do.
Look here, for the reasons: Why is overriding method parameters a violation of strict standards in PHP?
this is a little trick, but its peculiarity that does not give rise to safety problems, in the past or already used and tested.
I know it's not really what you needed but it solves your problem to the full while maintaining the safety and the forcing of the returns of the methods
class ClassA {}
class ClassB {
public function makeClassA_ClassB(ClassA $classA) : ClassA
{
return $classA;
}
function __call($function_name, $argument){
if ($function_name==="makeClassA" && $argument[0] instanceof ClassA ) return $this->makeClassA_ClassB($argument[0]);
}
}
class ClassANew {}
class ClassC extends ClassB {
public function makeClassA_ClassC(ClassANew $classA) : ClassANew
{
return $classA;
}
function __call($function_name, $argument){
if ($function_name==="makeClassA" && $argument[0] instanceof ClassANew ) return $this->makeClassA_ClassC($argument[0]);
}
}
$t=new ClassC();
$t2=new ClassANew();
var_dump($t->makeClassA($t2)); // object(ClassANew)#212 (0) { }
$t=new ClassB();
$t2=new ClassA();
var_dump($t->makeClassA($t2)); // object(ClassA)#212 (0) { }
Ok, so I finally figured out the problem. I had to keep the original referenced return types the same. After that it works fine now.
namespace Original;
class ClassExtra {}
class ClassA {
public function __construct($container, ClassB $classB) {}
}
class ClassB {
public function __construct(ClassExtra $classExtra) {}
}
class ClassC {
public $classB;
public $containers;
public function __construct(ClassB $classB) {
$this->classB = $classB;
}
public function container(string $container = 'default'): ClassA
{
$this->containers[$container] = new ClassA($container, $this->classB);
return $this->containers[$container];
}
}
Namespace Changes;
Class NewClassA extends \Original\ClassA {}
Class NewClassB extends \Original\ClassB {}
Class NewClassC extends \Original\ClassC {
public function container(string $container = 'default'): \Original\ClassA
{
$this->containers[$container] = new NewClassA($container, $this->classB);
return $this->containers[$container];
}
}
$classC = new \Original\ClassC(new \Original\ClassB(new \Original\ClassExtra()));
var_dump(get_class($classC->container('test')));
/* string(15) "Original\ClassA" */
$classC = new NewClassC(new NewClassB(new \Original\ClassExtra()));
var_dump(get_class($classC->container('test')));
/* string(17) "Changes\NewClassA" */
That should be possible:
// just an example
class ClassA {} // the class within the used package
class ClassANew {} // your own class
// ClassB is the parent class, the one in the package
class ClassC extends ClassB {
public function makeClassA(ClassA|ClassANew $classA)
{
return $classA;
}
}
Make sure that each class/interface has correct inheritance.
More details: https://www.php.net/manual/en/language.oop5.variance.php
However, you MUST NOT totally change the logic, of the parent's function. There is an extend/implementation of the object for some reason.
If you want to just have a method that shares only the name, do not implement the new object as an child class of the previous class. The class should be only inherited from the previous class if it shares the purpose.
An example, of what I am trying to say:
There is no meaning to make a class 'Countie' that implements 'Countable' just to have a method 'count':
class Countie implements \Countable {
private int $num = 0;
public function count() {
foreach ($i = 1; $i <= $this->num; $i++) {
echo $i;
}
}
}
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.
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 {...}
When defining the structure and inheriting Interface and/or Abstract Class, which one is the best practice? And why? Here are 2 examples:
Here is the example for [Interface] -> [Abstract Class] -> [Class]
Interface DataInterface
{
public function __construct($connection);
public function connected();
public function get();
}
Abstract class BaseData implements DataInterface
{
protected $connection;
public function __construct($connection)
{
$this->connection = $connection;
}
}
class UserData extends BaseData
{
public function exists()
{
return is_connected($this->connection);
}
public function get()
{
return get_data($this->connection);
}
}
$oUserData = new UserData(new Connection());
And here is the sample for [Abstract Class] -> [Class] without the Interface
Abstract class BaseData
{
protected $connection;
public function __construct($connection)
{
$this->connection = $connection;
}
abstract public function connected();
abstract public function get();
}
class UserData extends BaseData
{
public function exists()
{
return is_connected($this->connection);
}
public function get()
{
return get_data($this->connection);
}
}
$oUserData = new UserData(new Connection());
I am currently creating a small app (might grow larger) and confused on how to implement in the beginning correctly.
By the way, is this declaration for __construct() with parameter make sense in Interface?
public function __construct($connection);
Abstract classes defines an interface that must be implemented to the heirs of the abstract class. An Interface-Construct defines an interface that must be implemented by a class that implements the interface-construct, the implementation of the interface is not limited to a single interface, whereas class inheritance is coupled to a single (abstract) class.
Interfaces in PHP are intentionally used to allow typehints of an limited subset of an entire class interface. There is no reason for an interface on abstract classes aslong their receiver of instances of their heirs did not use them ( with typehinting or logical identification over instanceof / is_a ). The more valuable benefit of interface-constructs are the possibility of replacing an common implementation of an interfaces with a alternate implementation.
In case of your BaseData-Example, i recommend to drop the abstract idea and use a trait and seperate interfaces instead.
trait connectionBrokerConstructor {
protected $connection;
public function isConnected()
{
return $this->connection instanceof Connection;
}
public function setConnection(Connection $connection)
{
$this->connection = $connection;
}
}
interface connectable
{
public function setConnection(Connection $connection);
public function isConnected();
}
interface userDataRepositoryInterface
{
public function get();
}
class UserData implements connectable, userDataRepositoryInterface
{
use connectionBrokerConstructor;
public function __construct(Connection $connect = null)
{
$this->setConnection($connection);
}
public function get()
{
return array('something');
}
}
Really abstract classes and interfaces are different.
Consider an interface as a contract, it lays out the rules that other classes (which implement it) must follow.
Abstract classes on the other hand are more like starting points, which other classes can build on, hence why they are sometimes called base classes.
------- Edit with example
I'm not an expert on such things, but I've always just done interface -> class.
For example, here is a simple interface:
interface AnimalInterface {
public function all();
public function findBySlug($slug);
}
And here is the class which implements that interface (simplified):
class AnimalEloquentRepository implements AnimalInterface {
public function all()
{
return Animal::all();
}
public function findBySlug($slug)
{
return Animal::whereSlug($slug)->first();
}
}
I do often have a base class, which others extend, but I've only once used an abstract class in a real world app, and that ended up getting replaced.
I'm sure there are better ways to do things, but this has worked really well for me in the past.
My reputation doesn't allow comments, but this statement in tr0y's answer is misleading:
"Abstract classes defines an interface that must be implemented to the heirs of the abstract class."
One of the main differences between an interface and an abstract class is that you are not required to implement any of the methods of an abstract class in a class that extends it. It's quite common for the abstract class to have methods with default behavior and only provide those methods in the heirs if the default behavior is not what you want.
On the other hand, you are require to create all methods specified in an interface in any class that implements that interface.
Another difference is that methods in an interface cannot have a body, while methods in an abstract class must have a body.
In PHP, can I specify an interface to have fields, or are PHP interfaces limited to functions?
<?php
interface IFoo
{
public $field;
public function DoSomething();
public function DoSomethingElse();
}
?>
If not, I realize I can expose a getter as a function in the interface:
public GetField();
You cannot specify members. You have to indicate their presence through getters and setters, just like you did. However, you can specify constants:
interface IFoo
{
const foo = 'bar';
public function DoSomething();
}
See http://www.php.net/manual/en/language.oop5.interfaces.php
Late answer, but to get the functionality wanted here, you might want to consider an abstract class containing your fields. The abstract class would look like this:
abstract class Foo
{
public $member;
}
While you could still have the interface:
interface IFoo
{
public function someFunction();
}
Then you have your child class like this:
class bar extends Foo implements IFoo
{
public function __construct($memberValue = "")
{
// Set the value of the member from the abstract class
$this->member = $memberValue;
}
public function someFunction()
{
// Echo the member from the abstract class
echo $this->member;
}
}
There's an alternative solution for those still curious and interested. :)
Use getter setter. But this might be tedious to implement many getters and setters in many classes, and it clutter class code. And you repeat yourself!
As of PHP 5.4 you can use traits to provide fields and methods to classes, ie:
interface IFoo
{
public function DoSomething();
public function DoSomethingElse();
public function setField($value);
public function getField();
}
trait WithField
{
private $_field;
public function setField($value)
{
$this->_field = $value;
}
public function getField()
{
return $this->field;
}
}
class Bar implements IFoo
{
use WithField;
public function DoSomething()
{
echo $this->getField();
}
public function DoSomethingElse()
{
echo $this->setField('blah');
}
}
This is specially usefull if you have to inherit from some base class and need to implement some interface.
class CooCoo extends Bird implements IFoo
{
use WithField;
public function DoSomething()
{
echo $this->getField();
}
public function DoSomethingElse()
{
echo $this->setField('blah');
}
}
Interfaces are only designed to support methods.
This is because interfaces exist to provide a public API that can then be accessed by other objects.
Publicly accessible properties would actually violate encapsulation of data within the class that implements the interface.
You cannot specify properties in an interface : only methods are allowed (and make sense, as the goal of an interface is to specify an API)
In PHP, trying to define properties in an interface should raise a Fatal Error : this portion of code :
interface A {
public $test;
}
Will give you :
Fatal error: Interfaces may not include member variables in...