PHP interface problem - class not found - php

Hi I have a very simple class that implements an interface. Both the class and the interface are in the same file.
When I implement the interface I get a fatal error "Class not found", but when I remove the implements and then try to use the class I can use it fine???
Can anyone offer any advice on this?
Sorry here is some code that I am using to test at the moment:
$tester = new TypeOneTester();
$tester->test("Hello");
interface iTestInterface
{
public function test($data);
}
class TypeOneTester implements iTestInterface
{
public function test($data)
{
return $data;
}
}

Create an instance of your class after the class and the interface are defined, not before.
The order of definition in this case should be:
Interface
Class
Instance of Class (objects)

This is a (very poorly) documented limitation:
http://php.net/manual/pl/migration5.incompatible.php
In some cases classes must be declared before use. It only happens if some of the new features of PHP 5 (such as interfaces) are used. Otherwise the behaviour is the old.
I've filed a bug report nonetheless. IMO it should be fixed as it's inconsistent behaviour and the error message is not helpful for anyone who assumes as I did that PHP simply didn't care where you declare functions/classes. Come on, it's been there for over 10 years now...
https://bugs.php.net/bug.php?id=69665

smells like a bug in php. Make sure it's reproducible with the latest version and post to bugs.php.net.
Reproduce code
interface I {}
$a = new A;
$b = new B;
class A {
function __construct() { echo 'A'; }
}
class B implements I {
function __construct() { echo 'B'; }
}
Expected
AB
Actual:
A
Fatal error: Class 'B' not found...

That is because, php loading interface, and instantiate class class class object where there is a certain order and must be in a Php file, if the file is not in accordance with an order of 1. Require_one interface, 2. Require_one class

Related

PHP OOP Declaration of interface implementation compatibility

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.

unable to debug the output

Today i was reading design pattern and i tried to make a sample program which consist of a interface, two class which implement that interface and a main index class.let have a look at the code given below.
firstly the interface Iproduct
<?php
interface Iproduct
{
//Define the abstract method
public function apple();
public function mango();
}
the two class which implement the interface
<?php
// Including the interface
include_once 'Iproduct.php';
class Apple implements Iproduct
{
public function apple()
{
echo ("We sell apples!");
}
public function mango()
{
echo ("We do not sell Mango!");
}
}
<?php
// Include the interface Iprodduct
include_once 'Iproduct.php';
class Mango implements Iproduct
{
public function apple()
{
echo ("We do not sell Apple");
}
public function mango()
{
echo ("We sell mango!");
}
}
now the main class
<?php
include_once ('apple.php');
include_once ('Mango.php');
class UserProduct
{
public function __construct()
{
$apple_class_obj=new Apple();
$mango_class_obj=new Mango();
//echo("<br/> the apple class object: ".$apple_class_obj);
}
}
//creating the object of the UserProduct
echo ("creating the object!<br/>");
$userproduct_obj=new UserProduct();
?>
the output which i get when i execute the code is:
creating the object!
we sell apples!we sell mango
now the problem is that i am unable to get that how is the second output ie, we sell apple! and we sell mango! is being displayed.please let me know the reason
In the past (PHP before version 5), the method with the same name as the class is called when the object is created (PHP old-style constructor methods).
Because PHP is backwards compatible to that behavior, you see the output now.
For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, and the class did not inherit one from a parent class, it will search for the old-style constructor function, by the name of the class. Effectively, it means that the only case that would have compatibility issues is if the class had a method named __construct() which was used for different semantics. [Bold by me]
From: Constructors and Destructors in the PHP Manual
So what you experience is less a problem with the interface or the objects per-se, it's just some side-effect you're likely not aware of (this is really old).
To work around that, just implement a __construct() method in both classes so that the old-style constructor is not called any longer:
class Mango implements Iproduct
{
public function __construct() {}
...
An empty method per class is enough here to stop that.
You might be as well interested in:
What is the function __construct() used for? (Jan 2009)
Why are functions and methods in PHP case-insensitive? (May 2010)
Why is my constructor still called even if the class and constructor case are different? (Oct 2011)
in php 4x a method with the same name as the class was considered as the constructor. With php 5x the constructor is explicitly named __construct.
Your experiencing the outcome due to backward compatibility of PHP.

Under what circumstances is it possible that parent fields are not inherited?

I've got a curious bug (bugging me) today. There are three inheritance levels involved:
Grandpa:
abstract class Zend_Db_Table_Row_Abstract implements ArrayAccess,
IteratorAggregate
{
protected $_data = array();
/* snip */
}
Mom:
namespace Survey\Db\Table\Row;
class AbstractRow extends \Zend_Db_Table_Row_Abstract
{
/* snip */
}
Child:
namespace Survey\Db\Table\Row;
class SurveyItem extends AbstractRow implements ISkippable
{
/* snip */
}
Exception:
Type: ErrorException
Value: Undefined property: Survey\Db\Table\Row\SurveyItem::$_data
Location: [...]/Zend/Db/Table/Row/Abstract.php in handleError , line 177
Line 177 doesn't seem to be relevant, but I'm adding it just so you'd believe me ;)
if (!array_key_exists($columnName, $this->_data)) {
PHP 5.4.11, problem did NOT exist with PHP 5.4.8
When I saw the fix for Bug #63462 Magic methods called twice for unset protected properties, I thought, that wold solve the problem, since this bug leads to exactly the weird unexpected outcome I was seeing.
But it turns out, the problem still exists after updating to PHP 5.4.12. The likelyhood that there is another similar bug in PHP seems quite high.
Question:
I get the info that a protected field defined in the Grandpa is undefined in the Child. What scenarios can lead to such an outcome?
following snippet works flawlessly on PHP 5.4.9:
class A
{
protected $foo = 'hello';
public function bar()
{
echo $this->foo;
}
}
class B extends A {}
class C extends B {}
$c = new C();
$c->bar();
Please minimise your code step by step to this to see if/when problem occurs (I wonder why you haven't done it already)
If you are sure this worked on PHP 5.4.8 and does not work on PHP 5.4.11 then you found a bug in PHP and should be reporting it on php.net
Answer may be different (maybe it simply got 'unset' along the way).
Minimise your code and you will know.
If you don't want the parent field to inherit in the child class through object then declar the parent field as "static".

Can parameter types be specialized in PHP

Say we've got the following two classes:
abstract class Foo {
public abstract function run(TypeA $object);
}
class Bar extends Foo {
public function run(TypeB $object) {
// Some code here
}
}
The class TypeB extends the class TypeA.
Trying to use this yields the following error message:
Declaration of Bar::run() must be compatible with that of Foo::run()
Is PHP really this broken when it comes to parameter types, or am I just missing the point here?
This answer is outdated since PHP 7.4 (partially since 7.2).
The behavior you describe is called covariance and is simply not supported in PHP. I don't know the internals but I might suspect that PHP's core does not evaluate the inheritance tree at all when applying the so called "type hint" checks.
By the way, PHP also doesn't support contravariance on those type-hints (a feature commonly support in other OOP languages) - most likely to the reason is suspected above. So this doesn't work either:
abstract class Foo {
public abstract function run(TypeB $object);
}
class Bar extends Foo {
public function run(TypeA $object) {
// Some code here
}
}
And finally some more info: http://www.php.net/~derick/meeting-notes.html#implement-inheritance-rules-for-type-hints
This seems pretty consistent with most OO principals. PHP isn't like .Net - it doesn't allow you to override class members. Any extension of Foo should slide into where Foo was previously being used, which means you can't loosen constraints.
The simple solution is obviously to remove the type constraint, but if Bar::run() needs a different argument type, then it's really a different function and should ideally have a different name.
If TypeA and TypeB have anything in common, move the common elements to a base class and use that as your argument constraint.
I think this is by design: It is the point of abstract definitions to define the underlying behaviour of its methods.
When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility.
One could always add the constraint in code:
public function run(TypeA $object) {
assert( is_a($object, "TypeB") );
You'll have to remember or document the specific type limitation then. The advantage is that it becomes purely a development tool, as asserts are typically turned off on production servers. (And really this is among the class of bugs to be found while developing, not randomly disrupt production.)
The code shown in the question is not going to compile in PHP. If it did class Bar would be failing to honour the gurantee made by it's parent Foo of being able to accept any instance of TypeA, and breaching the Liskov Substitution Principle.
Currently the opposite code won't compile either, but in the PHP 7.4 release, expected on November 28 2019, the similar code below will be valid, using the new contravariant arguments feature:
abstract class Foo {
public abstract function run(TypeB $object); // TypeB extends TypeA
}
class Bar extends Foo {
public function run(TypeA $object) {
// Some code here
}
}
All Bars are Foos, but not all Foos are Bars. All TypeBs are TypeAs but not all TypeAs are TypeBs. Any Foo will be able to accept any TypeB. Those Foos that are also Bars will also be able to accept the non-TypeB TypeAs.
PHP will also support covariant return types, which work in the opposite way.
Although you cannot use whole class-hierarchies as type-hinting. You can use the self and parent keywords to enforce something similar in certain situations.
quoting r dot wilczek at web-appz dot de from the PHP-manual comments:
<?php
interface Foo
{
public function baz(self $object);
}
class Bar implements Foo
{
public function baz(self $object)
{
//
}
}
?>
What has not been mentioned by now is that you can use 'parent' as a typehint too. Example with an interface:
<?php
interface Foo
{
public function baz(parent $object);
}
class Baz {}
class Bar extends Baz implements Foo
{
public function baz(parent $object)
{
//
}
}
?>
Bar::baz() will now accept any instance of Baz.
If Bar is not a heir of any class (no 'extends') PHP will raise a fatal error:
'Cannot access parent:: when current class scope has no parent'.

Is there any way to detect the target class in static methods?

Below is an example class hierarchy and code. What I'm looking for is a way to determine if 'ChildClass1' or 'ChildClass2' had the static method whoAmI() called on it without re-implementing it in each child class.
<?php
abstract class ParentClass {
public static function whoAmI () {
// NOT correct, always gives 'ParentClass'
$class = __CLASS__;
// NOT correct, always gives 'ParentClass'.
// Also very round-about and likely slow.
$trace = debug_backtrace();
$class = $trace[0]['class'];
return $class;
}
}
class ChildClass1 extends ParentClass {
}
class ChildClass2 extends ParentClass {
}
// Shows 'ParentClass'
// Want to show 'ChildClass1'
print ChildClass1::whoAmI();
print "\n";
// Shows 'ParentClass'
// Want to show 'ChildClass2'
print ChildClass2::whoAmI();
print "\n";
I believe what you're referring to is a known php bug. Php 5.3 is aiming to address this issue with a new Late Static Binding feature.
http://www.colder.ch/news/08-24-2007/28/late-static-bindings-expl.html
Now that PHP 5.3 is widely available in the wild, I wanted to put together a summary answer to this question to reflect newly available techniques.
As mentioned in the other answers, PHP 5.3 has introduced Late Static Binding via a new static keyword. As well, a new get_called_class() function is also available that can only be used within a class method (instance or static).
For the purpose of determining the class as was asked in this question, the get_called_class() function is appropriate:
<?php
abstract class ParentClass {
public static function whoAmI () {
return get_called_class();
}
}
class ChildClass1 extends ParentClass {
}
class ChildClass2 extends ParentClass {
}
// Shows 'ChildClass1'
print ChildClass1::whoAmI();
print "\n";
// Shows 'ChildClass2'
print ChildClass2::whoAmI();
print "\n";
The user contributed notes for get_called_class() include a few sample implementations that should work in PHP 5.2 as well by making use of debug_backtrace().
Class identification is often a symptom of not well understood Polymorphism.
The clients of ChildClass1 and ChildClass2 shouldn't need to distinguish between them.
There's no place where any class should ask about someObject.whoAmI().
Whenever you have the urge to write if someObject.whoAmI() == 'ChildClass1' { do X(someObject) } you should really add an X() method to the ParentClass with various implementations in the various ChildClasses.
This kind of "run-time type identification" can almost always be replaced with properly polymorphic class designs.
As of PHP 5.3 it'll be possible with the use of the static keyword, but for now it isn't possible.
No. Wait for PHP 5.3.

Categories