|
Object InterfacesObject interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled. Interfaces are defined using the interface keyword, in the same way as a standard class, but without any of the methods having their contents defined. All methods declared in an interface must be public, this is the nature of an interface.
To implement an interface, the
Note:
A class cannot implement two interfaces that share function names, since it would cause ambiguity. Example 10.19. Interface example<?php See also the instanceof operator. Code Examples / Notes » language.oop5.interfacesm.kurzyna
You can have a class implementing two or more interfaces, just seperate them with a coma: <?php interface i_one { public one(); } interface i_two { public two(); } class oneANDtwo implements i_one, i_two { public one() {} public two() {} } ?> Of course all implemented interfaces will be tested, so one needs to have one() and two() in their class to avoid errors. russ dot collier
You can also specify class constants in interfaces as well (similar to specifying 'public static final' fields in Java interfaces): <?php interface FooBar { const SOME_CONSTANT = 'I am an interface constant'; public function doStuff(); } ?> Then you can access the constant by referring to the interface name, or an implementing class, (again similar to Java) e.g.: <?php class Baz implements FooBar { //.... } print Baz::SOME_CONSTANT; print FooBar::SOME_CONSTANT; ?> Both of the last print statements will output the same thing: the value of FooBar::SOME_CONSTANT erik dot zoltan
When should you use interfaces? What are they good for? Here are two examples. 1. Interfaces are an excellent way to implement reusability. You can create a general interface for a number of situations (such as a save to/load from disk interface.) You can then implement the interface in a variety of different ways (e.g. for formats such as tab delimited ASCII, XML and a database.) You can write code that asks the object to "save itself to disk" without having to worry what that means for the object in question. One object might save itself to the database, another to an XML and you can change this behavior over time without having to rewrite the calling code. This allows you to write reusable calling code that can work for any number of different objects -- you don't need to know what kind of object it is, as long as it obeys the common interface. 2. Interfaces can also promote gradual evolution. On a recent project I had some very complicated work to do and I didn't know how to implement it. I could think of a "basic" implementation but I knew I would have to change it later. So I created interfaces in each of these cases, and created at least one "basic" implementation of the interface that was "good enough for now" even though I knew it would have to change later. When I came back to make the changes, I was able to create some new implementations of these interfaces that added the extra features I needed. Some of my classes still used the "basic" implementations, but others needed the specialized ones. I was able to add the new features to the objects themselves without rewriting the calling code in most cases. It was easy to evolve my code in this way because the changes were mostly isolated -- they didn't spread all over the place like you might expect. marasek
What is not mentioned in the manual is that you can use "self" to force object hinting on a method of the implementing class: Consider the following interface: <?php interface Comparable {function compare(self $compare);} ?> Which is then implemented: <?php class String implements Comparable { private $string; function __construct($string) {$this->string = $string;} function compare(self $compare) {return $this->string == $compare->string;} } class Integer implements Comparable { private $integer; function __construct($int) {$this->integer = $int;} function compare(self $compare) {return $this->integer == $compare->integer;} } ?> Comparing Integer with String will result in a fatal error, as it is not an instance of the same class: <?php $first_int = new Integer(3); $second_int = new Integer(3); $first_string = new String("foo"); $second_string = new String("bar"); var_dump($first_int->compare($second_int)); // bool(true) var_dump($first_string->compare($second_string)); // bool(false) var_dump($first_string->compare($second_int)); // Fatal Error ?> dave
vbolshov at rbc dot ru: <?php error_reporting(E_ALL | E_STRICT); interface i { function f($arg); } class c implements i { function f($arg, $arg2 = null) { } } ?> > PHP doesn't generate a Fatal Error in this case, although > the method declaration in the class differs from that in the > interface. This situation doesn't seem good to me: I'd > prefer classes being strictly bound to their interfaces. It wouldn't make sense to prevent this as you can *always* pass more arguments to a function than it requires, and the function can still use func_get_args() & co. to get them if it wants. e.g. <?php class c implements i { function f($arg) { $args2 = (func_num_args() >= 2 ? func_get_arg(2) : null); } } ?> darealremco
To two notes below: There is one situation where classes and interfaces can be used interchangeably. In function definitions you can define parameter types to be classes or interfaces. If this was not so then there would not be much use for interfaces at all.
quickshiftin
to clarify (rather than just claim i think its a limitation) consider client code for the abstract class FifthInterface. Said client code must extend FifthInterface, thus using the only extension available to that class. really, i suppose it doesnt matter so much if we consider the client code could just implement FirstInterface and SecondInterface itself. Then, if there was a FifthInterface <?php interface FifthInterface { public function fifthInterface(); } ?> the client class could just implement that as well. hmmm.... I guess I just think interface inheritence affords cleaner designs. tobias_demuth
The statement, that you have to implement _all_ methods of an interface has not to be taken that seriously, at least if you declare an abstract class and want to force the inheriting subclasses to implement the interface. Just leave out all methods that should be implemented by the subclasses. But never write something like this: <?php interface Foo { function bar(); } abstract class FooBar implements Foo { abstract function bar(); // just for making clear, that this // method has to be implemented } ?> This will end up with the following error-message: Fatal error: Can't inherit abstract function Foo::bar() (previously declared abstract in FooBar) in path/to/file on line anylinenumber grigori kochanov
The engine does not recognise the class that implements an interface as declared in the code written before the class declaration is placed. This means that you can't place the declaration of a classes that implements an interfaces in the code beneath the creation of an instance. Tony2001 said this is an expected behaviour of Zend engine. Back to PHP 3 ;-) <?php var_dump(class_exists('validatorCheck')); //you don't write $obj = new validatorCheck() here class validatorCheck implements ArrayAccess { function offsetGet($key){} function offsetSet($key, $value) {} function offsetUnset($key) {} function offsetExists($offset) {} //class end } var_dump(class_exists('validatorCheck')); //an instance can be created only here ?> Result: bool(false) bool(true) spiritus.canis
Regarding the example by cyrille.berliat: This is not a problem and is consistent with other languages. You'd just want to use inheritance like so: <?php class AbstractClass { public function __ToString ( ) { return 'Here I am'; } } class DescendantClass extends AbstractClass {} interface MyInterface { public function Hello ( AbstractClass $obj ); } class MyClassOne implements MyInterface { public function Hello ( AbstractClass $obj ) { echo $obj; } } // Will work as Interface Satisfied $myDC = new DescendantClass() ; MyClassOne::Hello( $myDC ) ; ?> zedd
Regarding my previous note (04-Jul-2007 9:01): I noticed a minor but critical mistake in my explanation. After the link to the PHP manual page on class abstraction, I stated: "So by definition, you may only overload non-abstract methods." This is incorrect. This should read: "So by definition, you may only override non-abstract methods." Sorry for any confusion. php
Please note that the sentence "Note: A class cannot implement two interfaces that share function names, since it would cause ambiguity." _really_ means that it is not possible to do something like: <?php interface IA { public function a(); } interface IB { public function a(); } class Test implements IA, IB { public function a() { echo "a"; } } $o = new Test(); $o->a(); ?> lead to: PHP Fatal error: Can't inherit abstract function IB::a() (previously declared abstract in IA) It's important to note this because it is very unexpected behavior and renders many common Interface completly useless. warhog
on the post below: An interface is in fact the same like an abstract class containing abstract methods, that's why interfaces share the same namespace as classes and why therefore "real" classes cannot have the same name as interfaces. hayley watson
On an incidental note, it is not necessary for the implementation of an interface method to use the same variable names for its parameters that were used in the interface declaration. More significantly, your interface method declarations can include default argument values. If you do, you must specify their implementations with default arguments, too. Just like the parameter names, the default argument values do not need to be the same. In fact, there doesn't seem to be any functionality to the one in the interface declaration at all beyond the fact that it is there. <?php interface isStuffed { public function getStuff($something=17); } class oof implements isStuffed { public function getStuff($a=42) { return $a; } } $oof = new oof; echo $oof->getStuff(); ?> Implementations that try to declare the method as getStuff(), getStuff($a), or getStuff($a,$b) will all trigger a fatal error. chris
Note that you can extend interfaces with other interfaces since under-the-hood they are just abstract classes: <?php interface Foo { public function doFoo(); } interface Bar extends Foo { public function doBar(); } class Zip implements Bar { public function doFoo() { echo "Foo"; } public function doBar() { echo "Bar"; } } $zip = new Zip(); $zip->doFoo(); $zip->doBar(); ?> This is quite useful when you're using interfaces for identity more than the rigidity it places upon an API. You can get the same result by implementing multiple interfaces. An example of where I've used this in the past is with EventListener objects ala Java's Swing UI. Some listeners are effectively the same thing but happen at different times therefore we can keep the same API but change the naming for clarity. albert
Maybe this is a bit like cyrille.berliat's problem plus a somewhat solution. Let's say we want to create a queue class (or a stack, or a double linked list, the usual... :-). Wouldn't it be nice if we could define a generic interface or abstract (base) class that dictates the way specific queues have to look like ? Without having to specify the type of data to be queued. But we _do_ want to be strict about the type of data to be passed to a specific queue type. In other words: a bit of generic programming. Alas, it seems that Type Hinting and Interface/abstract don't get along :( But there might be a more runtime-involved solution. See below. So, this won't work: ------ abstract class Object {} // as PHP(5) doesn't have a super-Object-base-class class Cdata extends Object { } // i.e. Cdata IS-A Object interface Iqueue { public function enqueue(Object $data); } class Cmyqueue implements Iqueue { public function enqueue(Cdata $data) { } } $q = new Cmyqueue; $data = new Cdata; $q->enqueue($data); ------ Nor will this 'compile': ------ abstract class Object {} class Cdata extends Object {} abstract class Iqueue extends Object { abstract public function enqueue(Object $data); } class Cmyqueue extends Iqueue { public function enqueue(Cdata $data) { } } $q = new Cmyqueue; $data = new Cdata; $q->enqueue($data); --------- This however is possible: abstract class Object {} class Cdata extends Object { function __toString() { return('data'); } } abstract class Iqueue extends Object { abstract public function enqueue(Object $data); } class Cmyqueue extends Iqueue { public function enqueue(Object $data) { echo "enqueue '".$data->__toString()."'\n"; } } or: interface Iqueue { public function enqueue(Object $data); } class Cmyqueue implements Iqueue { .... } We could do our special Cmyqueue specific pre-processing before enqueu()ing. But the compiler won't warn us if we pass anything other than the object we expect to be passed. We'd have to do something runtime like this: class Cmyqueue extends Iqueue { private function checkObjectType(Object &$obj) { if (get_class($obj) !== 'Cdata') throw new Exception("You can only pass CData's to Cmyqueue"); } public function enqueue(Object $data) { $this->checkObjectType($data); echo "enqueue '".$data->__toString()."'\n"; } } hope this clears up some... mat.wilmots
interfaces support multiple inheritance <?php interface SQL_Result extends SeekableIterator, Countable { // new stuff } abstract class SQL_Result_Common { // just because that's what one would do in reality, generic implementation } class SQL_Result_mysql extends SQL_Result_Common implements SQL_Result { // actual implementation } ?> This code raises a fatal error because SQL_Result_mysql doesn't implement the abstract methods of SeekableIterator (6) + Countable (1) cyrille.berliat no spam free.fr
Interfaces and Type Hinting can be used but not with Inherintance in the same time : <? class AbstractClass { public function __ToString ( ) { return 'Here I\'m I'; } } class DescendantClass extends AbstractClass { } interface MyI { public function Hello ( AbstractClass $obj ); } class MyClassOne implements MyI { public function Hello ( AbstractClass $obj ) { echo $obj; } } // Will work as Interface Satisfied class MyClassTwo implements MyI { public function Hello ( DescendantClass $obj ) { echo $obj; } } // Will output a fatal error because Interfaces don't support Inherintance in TypeHinting //Fatal error: Declaration of MyClassTwo::hello() must be compatible with that of MyI::hello() ?> Something a little bit bad in PHP 5.0.4 :) nrg1981 {at} hotmail {dot} com
In case you would want to, a child class can implement an interface: <?php interface water { public function makeItWet(); } class weather { public function start() { return 'Here is some weather'; } } class rain extends weather implements water { public function makeItWet() { return 'It is wet'; } } $a = new rain(); echo $a->start(); echo $a->makeItWet(); ?> maikel
if you want to implement an interface and in addition you need to inherit, the correct order is: <?php class MyClassChildren extends MyClassParent implements MyInterface { } ?> hayley watson
If it's not already obvious, it's worth noticing that the parameters in the interface's method declaration do not have to have the same names as those in any of its implementations. More significantly, default argument values may be supplied for interface method parameters, and they have to be if you want to use default argument values in the implemented classes: <?php interface isStuffable { public function getStuffed($ratio=0.5); } class Turkey implements isStuffable { public function getStuffed($stuffing=1) { // .... } } ?> Note that not only do the parameters have different names ($ratio and $stuffing), but their default values are free to be different as well. There doesn't seem to be any purpose to the interface's default argument value except as a dummy placeholder to show that there is a default (a class implementing isStuffable will not be able to implement methods with the signatures getStuffed(), getStuffed($a), or getStuffed($a,$b)). prometheus
If I run the belowing code, I get an error message. <?php /** * Testing of method overrideing on interfaces */ interface IFoo { public function Foo(); } interface IBar extends IFoo { public function Foo($bar); } ?> The error message says: Fatal error: Can't inherit abstract function IFoo::Foo() (previously declared abstract in IBar) in D:\www\svn\virgilius\interface_or_test.php on line 12 So I don't understand that if method overriding works fine in class instances, but not in interfaces. BTW I think that is a typical situation when a standard method expanded by new parameters in the later interface instances. I know, I can do a workaround with the func_get_* functions, but it's a big ugly hack I think. If I make a big class-hierarchie, I must make a lot of the above ugly think maybe, in a lot of methods, maybe. So I prefer to droping all my interfaces and don't use ever again this stucture, because it's only make difficult to develop rather then it's make relieve and clean logically and overviewable. Peace. nuying117
If a class implements two interfaces , but these two interfaces have a same method,for example <?php interface TestInterface1 { function testMethod1(); function testMethod2(); } interface TestInterface2 { function testMethod2(); function testMethod3(); function testMethod4(); } class ImplementClass implements TestInterface1,TestInterface2 { function __construct() { echo "I am constructor\r\n"; } function __destruct() { echo "I am destructor\r\n"; } function testMethod1() {} function testMethod2() {} function testMethod3() {} function testMethod4() {} } ?> It will cause a fatal error! vbolshov
Consider the following: [vbolshov@localhost tmp]$ cat t.php <?php error_reporting(E_ALL | E_STRICT); interface i { function f($arg); } class c implements i { function f($arg, $arg2 = null) { } } ?> [vbolshov@localhost tmp]$ php t.php [vbolshov@localhost tmp]$ PHP doesn't generate a Fatal Error in this case, although the method declaration in the class differs from that in the interface. This situation doesn't seem good to me: I'd prefer classes being strictly bound to their interfaces. florian_mrt
Classes can adopt interfaces, without the interface-specified functions, if they are inherited from parent classes. <?php interface object_interface { public function object_function(); } abstract class abstract_object { public function object_function() { print ("This class is: abstract_object"); } } class child_object extends abstract_object implements object_interface { } $OB = new child_object; $OB->object_function(); ?> marcus
Classes and interface names share a common name space, so you can't have a class and an interface with the same name, even though the two can never be used ambiguously (i.e. there are no circumstances in which a class and an interface can be used interchangeably). e.g. this will not work: interface foo { public function bling(); } class foo implements foo { public function bling() { } } You will get a 'Cannot redeclare class' error, even though it's only been declared as a class once. sebastian mendel
also see: class_implements() at: http://www.php.net/manual/en/function.class-implements.php |
Change LanguageIntroduction The Basics Autoloading Objects Constructors and Destructors Visibility Scope Resolution Operator (::) Static Keyword Class Constants Class Abstraction Object Interfaces Overloading Object Iteration Patterns Magic Methods Final Keyword Object cloning Comparing objects Reflection Type Hinting Late Static Bindings |