Consider the following PHP interfaces:
interface Item {
// some methods here
}
interface SuperItem extends Item {
// some extra methods here, not defined in Item
}
interface Collection {
public function add(Item $item);
// more methods here
}
interface SuperCollection extends Collection {
public function add(SuperItem $item);
// more methods here that "override" the Collection methods like "add()" does
}
I'm using PHPStorm, and when I do this, I get an error in the IDE that basically states the definition for add() in SuperCollection is not compatible with the definition in the interface it extends, Collection.
In one way, I can see this being a problem, as the signature of the method does not match the one it "overrides" exactly. However, I do feel that this would be compatible, as SuperItem extends Item, so I would view add(SuperItem) the same as add(Item).
I'm curious as to if this is supported by PHP (version 5.4 or above), and maybe the IDE has a bug that doesn't properly catch this.
No, I'm pretty sure PHP doesn't support this, in any version, and it would rather defeat the point of an interface.
The point of an interface is that it gives you a fixed contract with other code that references the same interface.
For example, consider a function like this:
function doSomething(Collection $loopMe) { ..... }
This function expects to receive an object that implements the Collection interface.
Within the function, the programmer would be able to write calls to methods that are defined in Collection, knowing that the object would implement those methods.
If you have an overridden interface like this, then you have a problem with this, because a SuperCollection object could be passed into the function. It would work because it also is a Collection object due to the inheritance. But then the code in the function could no longer be sure that it knows what the definition of the add() method is.
An interface is, by definition, a fixed contract. It is immutable.
As an alternative, you could consider using abstract classes instead of interfaces. This would allow you to override in non-Strict mode, although you'll still get errors if you use Strict Mode, for the same reasons.
As a workaround I'm using PHPDoc blocks in interfaces.
interface Collection {
/**
* #param Item $item
*/
public function add($item);
// more methods here
}
interface SuperCollection extends Collection {
/**
* #param SuperItem $item
*/
public function add($item);
// more methods here that "override" the Collection methods like "add()" does
}
This way, in case you are properly using interfaces, IDE should help you catch some errors. You can use similar technique to override return value types as well.
PHP 7.4, released November 2019 has improved type variance.
The code from the question remains invalid:
interface Item {
// some methods here
}
interface SuperItem extends Item {
// some extra methods here, not defined in Item
}
interface Collection {
public function add(Item $item);
// more methods here
}
interface SuperCollection extends Collection {
public function add(SuperItem $item); // This will still be a compile error
// more methods here that "override" the Collection methods like "add()" does
}
Because the Collection interface guarantees that anything that implements it can accept any object of type Item as the parameter of add.
However, the following code is valid in PHP 7.4:
interface Item {
// some methods here
}
interface SuperItem extends Item {
// some extra methods here, not defined in Item
}
interface Collection {
public function add(SuperItem $item);
// more methods here
}
interface SuperCollection extends Collection {
public function add(Item $item); // no problem
// more methods here that "override" the Collection methods like "add()" does
}
In this case Collection guarantees that that it can accept any SuperItem. Since all SuperItems are Items, SuperCollection also makes this guarantee, while also guaranteeing that it can accept any other type of Item. This is known as a Contravariant method parameter type.
There is a limited form of type variance in earlier versions of PHP. Assuming other interfaces are as in the question, the SuperCollection may be defined as:
interface SuperCollection extends Collection {
public function add($item); // no problem
// more methods here that "override" the Collection methods like "add()" does
}
This can be interpreted as meaning any value whatsoever may be passed to the add method. That of course includes all Items, so this is still type safe, or it can be interpreted as meaning that an unspecified class of values, generally documented as mixed may be passed and the programmer needs to use other knowledge of exactly what can work with the function.
You cannot change the methods arguments.
http://php.net/manual/en/language.oop5.interfaces.php
Extending interface is not allowed to change method definitions. If your SuperItem is extending Item, it should be passing through classes implementing Collection interface without problems.
But based on what you really want to do, you can try:
Create interface with slightly different methods for SuperItem and implement that:
interface SuperCollection extends Collection {
public function addSuper(SuperItem $superItem);
}
Use decorator pattern to create almost same interface without extending:
interface Collection {
public function add(Item $item);
// more methods here
}
interface SuperCollection {
public function add(SuperItem $item);
// more methods here that "override" the Collection methods like "add()" does
}
Then decorator (abstract) class, which will use this interface:
class BasicCollection implements Collection {
public function add(Item $item)
{
}
}
class DecoratingBasicCollection implements SuperCollection {
protected $collection;
public function __construct(Collection $collection)
{
$this->collection = $collection;
}
public function add(SuperItem $item)
{
$this->collection->add($item);
}
}
The problem is not in the IDE. In PHP you cannot override a method. And the compatibility is only in the opposite direction - you can safely expect an instance of the parent class and receive a subclass. But when you expect a subclass, you cannot be safe if you receive the parent class - the subclass may define methods that do not exist in the parent. But still, you can't override the method
When I have a method that I may need to overload (which PHP does not support), I make sure that one of the method arguments (usually the last) is an array. In this way I can pass whatever I need to. I can then test within the function for various array elements to tell me what routine in the method I need to perform, usually in a select/case.
Related
I have a general problem with this use case: I have a class A. This class has a non-abstract method doStuffCallback() which could be overridden but it's not necessary for every subclass. But: I want to ensure that if the method is overriden the subclass-method must call the parents method.
Example:
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
protected function doStuffCallback() {
// IMPORTANT CODE HERE
}
}
class B extends A {
protected function doStuffCallback() {
parent::doStuffCallback(); // I want to enforce this because the parents method code is important
// ALSO IMPORTANT CODE
}
}
Because the overridden method does the same thing it would be very ugly to define two methods for the same responsibility and a private helper-method which calls both. Like this:
abstract class A {
private function doStuff() {
$this->callDoStuffCallback();
}
private function callDoStuffCallback() {
$this->internalDoStuffCallback();
$this->doStuffCallback();
// This is VERY ugly
}
private function internalDoStuffCallback() {
// IMPORTANT CODE HERE
}
protected function doStuffCallback() {}
}
class B extends A {
protected function doStuffCallback() {
// IMPORTANT CODE
}
}
This is really ugly and laborious. So my question: Is there a way in PHP to force overriden methods to call the parents method?
No. There is no such language feature in PHP; this restriction is not possible in most subtype-'OO' languages.
Instead programs must rely on explicit documentation contracts; and hopefully, unit testing to ensure conformance.
Guards may also be employed such that, at some point by and by when a method on the parent class is used, it could throw an exception if the 'current state' is not valid (eg. such and such a method has not been called yet). This may also be made more explicit by making the subclass required to call (as defined in the documentation contract) some special method, instead of simply the overriden super method. However, such is outside of any type system.
While the self:: scope could be used (eg. call non-overriden method which calls overriden method), this would involve further magic (eg. some stack state) to avoid infinite recursion loops; and it would be as easy to accidentally omit usage.
My recommendation is to call a (private) method that calls this 'maybe overriden' method in relationship to whatever logic applies, as shown in the example (although hopefully with more task specific tames). Then the (protected) overriden method is not expected or required to handle any of the special logic itself; nor is it meant to be called directly outside of the context established by the parent class - it is just what it currently claims to be, a special callback.
I tend to disagree with "This is VERY ugly". It is the standard way of handling this use case and a variant of the Template Method Pattern.
Now I am just guessing because you did not provide a real example but if you say that the two methods "do the same thing", there might be something wrong with your design. If they do the same thing, why is calling the parent implementation necessary if the subclass does the same thing in a different way? To me it sounds like the method actually does more than one thing and you might be able to break it down into several parts that can be overridden individually (or not, then make them private or final).
I know this is an old topic but I was asking myself the same question and what I did is :
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
final protected function doStuffCallback() {
// IMPORTANT CODE HERE
$this->callNewFunction();
}
abstract protected function callNewFunction();
}
class B extends A {
protected function callNewFunction() {
// ALSO IMPORTANT CODE
}
}
So basically I would mark as "final" the function you wish to force the code for every child and then call a new "Abstract" function to force the childs to implement it. If you do not wish to force the new "Abstract" function, simply don't make it abstract.
Edit : This is basically #Fabian Schmengler's answer but more concrete with your example.
No, you can access, you can use method for parent, like this
<?php
class A {
function s1($p1) {
echo 's1: '.$p1;
}
}
class B extends A {
public function callParent($method, $p1) {
parent::$method($p1);
}
}
$b = new B();
$b->callParent('s1', 'param1');
or replace extending on magic methods __call and etc. https://github.com/StagnantIce/php_extend_magic/blob/master/AExtendClass.php
From the docs page http://php.net/manual/en/language.oop5.typehinting.php
If class or interface is specified as type hint then all its children or implementations are allowed too.
But:
class PimpleChild extends Pimple {
//...
}
interface Pimple_Config {
public function configure(Pimple $container);
}
class PimpleConfigurer_Factories implements Pimple_Config {
public function configure(PimpleChild $container) {
//...
}
}
returns fatal error. Why?
If I am not mistaken you get this error:
Declaration of PimpleConfigurer_Factories::configure() must be compatible with Pimple_Config::configure(Pimple $container) ...
Which means: If you define a method in a super class or in an interface, all sub classes (or classes implementing the interface) must use exactly this definition. You cannot use another type here.
As for your quote from the documentation:
If class or interface is specified as type hint then all its children or implementations are allowed too.
This only means that you can pass a variable which is of a certain type or all its children.
For example: Say you have the following classes:
class Car {
protected $hp = 50;
public function getHp() { return $this->hp; }
}
class SuperCar extends Car {
protected $hp = 700;
}
And a function (or method, no difference there) with type hint:
function showHorsePower(Car $car) {
echo $car->getHp();
}
You can now pass all objects of type Car and all its sub classes (here SuperCar) to this function, like:
showHorsePower(new Car());
showHorsePower(new SuperCar());
From the same typehinting section you linked to:
The class implementing the interface must use the exact same method signatures as are defined in the interface. Not doing so will result in a fatal error.
For the method signatures to be the same, they must contain the exact same typehints. And also relevant because it is similar...
From the OOP Basics - extends section of the manual:
When overriding methods, the parameter signature should remain the same or PHP will generate an E_STRICT level error. This does not apply to the constructor, which allows overriding with different parameters.
In this question I would like to discuss a problem related to building a collection of homogeneous objects from a class using a transformer function that transforms a passed array or other sort of collection. The problem lies in the fact that I want to be able to see from which class are the objects in a collection when doing the transofrmation and at the same time avoid using statics as we all know they are kind of tricky and the general recommendation is to avoid them.
The scenario is the following:
There is an abstract class that does some common parsing of data (formatting dates, strings, floats, etc.) called AbstractData. Its purpose is to be extended by more concrete classes which make use of the abstract functions and hold the parsed data.
The concrete class uses a mapping array which tells how given raw data has to be parsed using the functions from the abstract class.
Currently what is being done to create a collection of such concrete class objects is the following (take care that the constructor of the Concrete class takes single row of data which it parses automatically using the defined mapping scheme):
collection = [];
foreach($rows as $row) {
collection = new ConcreteClass($row);
}
What I have here basically is just an array of those objects, but I was wondering what would be the best way to keep a more structured collection the same way you could do using generics in Java like List<ConcreteClass> collection = new List<ConcreteClass>(row);
Right now what I did was to make a static "factory" function in the abstract class:
public static function factory($data = null) {
return new static($data);
}
And a function that creates the "processed" collection:
public function createCollectionFromRawData($rows) {
$collection = [];
foreach($rows as $row) {
$collection[] = new static($row);
}
return $collection;
}
And call the concrete class like this: ConcreteClass::factory()->createCollectionFromRawData($rows)
And although it allows for better reading in a way it is a bit redundant since it does not separate concerns and additionally I have to create an empty object of the ConcreteClass just to be able to invoke the non-static createCollectionFromRawData function which I would like to avoid doing.
I was thinking something in the lines of involving DI to solve the problem but I am not really sure what exactly I can do.
I don't see the harm in using the late static binding functions I use them heavily in an ORM i have written but i do record the class name in a var on the class at each level because I have needed it for some tasks. I think you are trying to get a collection of items dependent on what you class you statically give the factory? Here is my crack at solving what I think you are asking. I do this by always using the public method on the abstract class, and defining the protected method on the class you are building as each of these may handle the input differently.
abstract class AbstractData {
protected $_abstractClassData;
public static final function factory($rawData)
{
return static::_createCollectionFromRawData($rawData);
}
}
class ConcreteClass extends AbstractData {
protected $_concreteClassData;
protected static function _createCollectionFromRawData($rows) {
$collection = array();
foreach($rows as $row) {
$collection[] = new static($row); //If you havnt defined a constructor on this class it will use your AbstractData one.
}
return $collection;
}
}
$collection = ConcreteClass::factory($rawData);
I have the following OOP structure:
<?php
interface AnimalInterface
{
public function getName();
}
class Dog implements AnimalInterface
{
public function getName() {
return 'dog';
}
public function makeFriends()
{
echo 'I have friends now :)';
}
}
class Cat implements AnimalInterface
{
public function getName() {
return 'cat';
}
public function hateFriends()
{
echo 'I cant make friends :(';
}
}
interface AnimalDoInterface
{
public function makeFriend(AnimalInterface $animal);
}
class DogFriend implements AnimalDoInterface
{
public function makeFriend(Dog $dog)
{
$dog->makeFriends();
}
}
class CatFriend implements AnimalDoInterface
{
public function makeFriend(Cat $cat)
{
$cat->hateFriends();
}
}
Now PHP's manual on Object Interfaces says:
The class implementing the interface must use the exact same method signatures as are defined in the interface. Not doing so will result in a fatal error.
Why is this the case? Am I misunderstanding interfaces completely? Surely I should be able to declare AnimalDoInterface::makeFriend with anything that is the interface or an implementation of that interface? In this case it should technically be compatible as Cat implements AnimalInterface, which is what it's expecting.
Regardless of whether I am getting my OOP wrong, is there a way to implement this in PHP?
So it seems I wasn't clear enough, my bad for that. However, basically what I'm trying to achieve is to have the implementations of AnimalDoInterface to be more restrictive than it's interface says. So in this case, I'd like DogFriend::makeFriend to only allow the Dog class as it's argument, which in my mind should be acceptable as it implements the AnimalInterface, and the CatFriend to allow a Cat class, which again, same thing.
EDIT: fixed the classes, also added what I'm trying to achieve.
EDIT 2:
So at the moment, the way I'd have to implement it is as following:
class DogFriend implements AnimalDoInterface
{
public function makeFriend(AnimalInterface $dog)
{
if(!($dog instanceof Dog)) {
throw new \Exception('$dog must be of Dog type');
}
$dog->makeFriends();
}
}
class CatFriend implements AnimalDoInterface
{
public function makeFriend(AnimalInterface $cat)
{
if(!($dog instanceof Cat)) {
throw new \Exception('$dog must be of Cat type');
}
$cat->hateFriends();
}
}
I'd like to have to avoid this extra check for the class type.
An interface's only job is to enforce the fact that two objects behave in an identical way, regardless of how they implement that behaviour. It is a contract stating that two objects are interchangeable for certain specific purposes.
(Edit: This part of the code has been corrected, but serves as a good introduction.) The interface AnimalInterface defines the behaviour (function) getAnimalName(), and any class claiming to implement that interface must implement that behaviour. class Dog is declared with implements AnimalInterface, but doesn't implement the required behaviour - you can't call getAnimalName() on instances of Dog. So we already have a fatal error, as we have not met the "contract" defined by the interface.
Fixing that and proceeding, you then have an interface AnimalDoInterface which has the defined behaviour (function) of makeFriend(AnimalInterface $animal) - meaning, you can pass any object which implements AnimalInterface to the makeFriend method of any object which implements AnimalDoInterface.
But you then define class DogFriend with a more restrictive behaviour - its version of makeFriend can only accept Dog objects; according to the interface it should also be able to accept Cat objects, which also implement AnimalInterface, so again, the "contract" of the interface is not met, and we will get a fatal error.
If we were to fix that, there is a different problem in your example: you have a call to $cat->hateFriends(); but if your argument was of type AnimalInterface or AnimalDoInterface, you would have no way to know that a hateFriends() function existed. PHP, being quite relaxed about such things, will let you try that and blow up at runtime if it turns out not to exist after all; stricter languages would only let you use functions that are guaranteed to exist, because they are declared in the interface.
To understand why you can't be more restrictive than the interface, imagine you don't know the class of a particular object, all you know is that it implements a particular interface.
If I know that object $a implements AnimalInterface, and object $b implements AnimalDoInterface, I can make the following assumptions, just by looking at the interfaces:
I can call $a->getName(); (because AnimalInterface has that in its contract)
I can call $b->makeFriend($a); (because AnimalDoInterface has in its contract that I can pass anything that implements AnimalInterface)
But with your code, if $a was a Cat, and $b was a DogFriend, my assumption #2 would fail. If the interface let this happen, it wouldn't be doing its job.
The reason all classes implementing an interface must have the same methods is so that you can call that method on the object regardless of which subtype is instantiated.
In this case, you have a logical inconsistency because two subtypes, Cat and Dog, have different methods. So you can't call makeFriends() on the object, because you don't know that the object has that method.
That's the point of using interfaces, so you can use different subtypes, but at the same time you can be sure of at least some common methods.
One way to handle this in your case is to make sure Cat implements the same method, but make the method throw an exception at runtime, indicating that it's not possible. This allows the interface to be satisfies at compile time (I know PHP doesn't have a compiler, but this is mimicking languages like Java that do the interface checking at compile time).
class Cat implements AnimalInterface
{
public function makeFriends()
{
throw new RuntimeException('I cant make friends :(');
}
}
A class which implements AnimalDoInterface must have a makeFriend method which takes any object which implements AnimalInterface. In your case, trying to declare
class DogFriend implements AnimalDoInterface {
public function makeFriend(Dog $foo) { }
}
will not accurately implement this, since it should always be safe to pass anything which implements AnimalInterface to the makeFriend method of anything which implements AnimalDoInterface.
Not sure if my title is correct cause I am not even sure I am using the correct terms.
I have a class that has a property that is an object. When setting this property the object has to be created. My question is how do I do this without tight coupling?
Example:
class A
{
protected $_depending;
protected $_somePropertyObject;
public function __construct(\Lib\Dependency $depending)
{
$this->_setDepending($depending);
}
protected function _setDepending(\Lib\Dependency $depending)
{
$this->_depending = $depending;
}
public function setSomeProperty($someProperty)
{
// I want to prevent this
$this->_somePropertyObject = new \Lib\some\Object($someProperty);
}
}
I could just pass the required object through the construct but what happens more are needed?
When if I understand correctly the factory pattern, what would this change? I would still need to create the object somewhere? Not the object itself but the factory. Again tight coupling? Seems endless to me. When re factoring class(es) it however is isolated where and how the class(es) are made.
If I set the setSomeProperty function to only accept \Lib\some\Object then is still needs to be created by the parent object that is passing it to begin with. Seems only to shift the placement of where it is created?
Hopefully I am clear enough in what I am trying to ask.
Thanks in advance!
EDIT What I am asking is the sequence of what is created when,where,why.
The purpose of a factory in dependency injection patterns is to produce instances for another instance, without that other instance needing to know how to produce it.
At its core, a "factory" is just an object-returner: something that returns an instance when invoked.
This is easier to see in more capable languages. For example in Python classes are callable (there is no new operator), and invoking a class produces an instance of the class. So classes can be their own factories if the class requires no arguments. Likewise any zero-argument function that returns an instance can be considered a factory. This makes dependency injection very clear and free-of-boilerplate.
In more rigid languages (Java/C++/C# static-typed tradition, or where classes or functions are not completely first-class like in PHP), you need to obscure dependency injection behind a "pattern", because "design patterns" are missing language features. In PHP 5.3+ you can use a closure as a factory, or you can go the Java/C# way and define a FactoryInterface and a new class per factory.
For example, with your class, you could do this:
class Aprime extends A
{
public function setSomeProperty($somePropertyFactory)
{
$this->_somePropertyObject = $somePropertyFactory();
}
}
In this class, setSomeProperty requires a zero-argument callable "factory", which you could produce like this:
$other_dep_factory = function(){ return new SomeOtherClass(); };
Or like this:
class ClassFactory {
function __construct($classname, $args=array()) {
$this->class = new ReflectionClass($classname);
$this->args = $args;
}
function __invoke() {
return $this->class->newInstanceArgs($this->args);
}
}
$other_dep_factory = new ClassFactory('SomeOtherClass');
Prior to PHP 5.3, you need to do it like Java would:
interface IObjectFactory {
function getObject();
}
// this B-and-D interface is optional
// it has no body because PHP doesn't support
// type-hinting return values
interface ISomeOtherClassFactory {}
class SomeOtherClassFactory implements ISomeOtherClassFactory {
function getObject() {
return new SomeOtherClass();
}
}
class Aprime extends A
{
public function setSomeProperty(ISomeOtherClassFactory $somePropertyFactory)
{
$this->_somePropertyObject = $somePropertyFactory->getObject();
}
}
$other_dep_factory = new SomeOtherClassFactory();
$myAprimeObject->setSomeProperty($other_dep_factory);
So when do you use a factory? Whenever an object needs to create another object. If the object just needs to use another object, just pass in an instance.
I like to use the Factory Pattern when you need to collect "information" to create the object that's stored in $_somePropertyObject. For instance let's say you have to assign values to some properties to instantiate it or run a couple of methods right after you instantiate it.
Also, you'll want to consider whether you might need to later change the inheritance tree. If you might be assigning $_somePropertyObject a \Lib\some\Object now, you might find yourself wishing you could easily swap it out for a \Lib\some\FancyObject later. If you use Dependency Injection, you can easily swap subtypes.
Here's a primer: http://net.tutsplus.com/tutorials/php/the-whens-and-whys-for-php-design-patterns/
Also, too: https://stackoverflow.com/a/2083455/1121827