I was wondering if it is possible to use interface parameters in PHP functions / methods.
I'm used to coding in .Net and using .Net this is possible, such as having the following interface:
interface IVehicleDataProvider
{
public void Create(IVehicle Vehicle);
}
Then I could implement this in a class as such:
class CarDataProvider : IVehicleDataProvider
{
public void Create(Car Car)
{
//do something
}
}
or
class TruckDataProvider : IVehicleDataProvider
{
public void Create(Truck Truck)
{
//do something
}
}
as long as Car or Truck implements an IVehicle interface.
Can the same thing be done in PHP?
No, you can't define one type in the interface, and a different one (even though it's a subclass) in the implementor, the implementor must follow the interface completely.
But even if you define
function create(IVehicle $vehicle);
You can still pass in Cars and Trucks.
No it will not work becouse the declaration in the class must be fully compatible with the interface declaration so you have to use IVehicle as parameter type.
Yes, you can use interfaces in PHP 5, although they are still relatively immature. For the example above, you would use something like the following:
interface IVehicleDataProvider
{
public function create(IVehicle $vehicle);
}
class CarDataProvider implements IVehicleDataProvider
{
public function create(IVehicle $car) {
//do something
}
}
PHP does not support return type declaration, so you cannot declare a function void (although you should make note of the return type in the function documentation).
You also cannot extend an interface, so if you declare that the create function in the IVehicleDataProvider interface accepts an instance of IVehicle, then the CarDataProvider::create, function must accept an instance of the IVehicle interface.
Related
Is there any chance there is an equivalent of Objective C Categories in PHP?
If all you want to do is break a huge class definition up over multiple files, and it's your class, then you can do that with traits. Just define some of the methods in a trait in a different file and use it in your class:
trait FooBar_ExtraMethods {
function foo () { return 'qux'; }
}
class FooBar {
use FooBar__ExtraMethods;
function bar () { return 'baz'; }
}
But if you want to add methods to somebody else's class, then there's simply no way to do that with vanilla PHP. Your choices are:
Live with the fact that this isn't possible and just write a function that takes instances of the class instead of extending it.
Use an extension to add the functionality into the language. Right now, the only contender is Dmitry Zenovich and Sara Golemon's Runkit. Zenovich's fork currently seems to be better-maintained and generally superior to Golemon's (although Golemon's is the one hosted on PECL), and the instructions below use Zenovich's fork.
Suppose I have an existing user-defined class Foo...
class Foo {
function methodA($arg) { return 2*$arg; }
}
I can add a method to it like this:
runkit_method_add('Foo', 'methodC', function ($arg) {
return 5 * $this->methodA($arg);
});
and call it like an ordinary method:
$f = new Foo;
echo $f->methodC(2); // 20
A couple of caveats:
You can't add methods to built-in classes. So if you want to use this to extend library-defined classes, you're good, but if you want to extend built-in classes like DateTime, you're out of luck.
This isn't remotely idiomatic - indeed, Runkit's tagline is "For all those things you.... probably shouldn't have been doing anyway.....". I leave it to your judgement whether to let that deter you from doing it.
It looks like a trait.
trait CarMaintenance{
public function needsOilChange(){}
public function changeOil(){}
public function rotateTires(){}
public function jumpBatteryUsingCar(){}
}
class Car {
use CarMaintenance;
public function startEngine() {}
public function drive() {}
public function turnLeft() {}
public function turnRight() {}
}
But traits could be reused in other class and could have their own hierarchy tree.
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.
I'm comming from C++ and from all I've read in the manual and code examples, none seem to separate a class method declaration from its definition. Is this not possible in PHP? Dosn't this lead to very hard-to-read and cluttery interfaces?
Thanks
EDIT:
I want something like this:
class MyClass
{
public function Foo();
};
MyClass::Foo()
{
echo "O-hoy!";
}
When not using interfaces, you are right. Like in Java, the class definition is the declaration. However, (also like Java), you have the interface available that you can use:
From the documentation:
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}
// Implement the interface
// This will work
class Template implements iTemplate
{
private $vars = array();
...
}
it is perfectly legal to put them in different files. The class definition though, will always be in one file. You cannot use the partial keyword as you can in C#.
This concept is not necessary in PHP. If you want to get a clean interface, you might define one. http://php.net/manual/en/language.oop5.interfaces.php
I'm trying to create a PHP file that calls a function in another file. Some sample code:
Interface code:
interface AJAXDispatcher {
static function dispatch($action);
}
Implementation:
class myAJAX implements AJAXDispatcher {
static function dispatch($action) {
if ($action === "action1") {
do_something();
}
This seems ok to me. I try to call it by first importing the file that it's in. I'm trying to make it independent of the name of the class so that I can do something like this:
AJAXDispatcher::dispatch($action);
Thought this would work as myAJAX would inherit from AJAXDispatcher, but I get the following error:
Fatal error: Cannot call abstract method AJAXDispatcher::dispatch() in ....
Anyone know what I'm doing wrong?
Interfaces with static methods don't make any sense, because to call a static method you (usually) need to know the class name.
Instead, you should make the method non-static and create an instance of myAJAX somewhere. The code that calls the AJAXDispatcher receives the instance and calls it. You can use type hinting to ensure you are getting the right instance.
interface AJAXDispatcher {
public function dispatch($action);
}
class myAJAX implements AJAXDispatcher {
public function dispatch($action) {
do_something();
}
}
class Controller {
private $dispatcher;
public function __construct(AJAXDispatcher $dispatcher) {
$this->dispatcher = $dispatcher;
}
public function action($action) {
$this->dispatcher->dispatch($action);
}
}
$dispatcher = new myAJAX();
$controller = new Controller($dispatcher);
$controller->action('index');
This example uses the Dependency Injection design pattern.
An interface has no method implementation. It only defines a public API that classes have to implement. How they implement it, is up to the concrete classes. Thus, you cannot call methods of an interface directly, because there is no code to call. You have to call the method on the implementing class.
Have a look at the PHP Manual on Interfaces.
No, you can't do that. There are several things wrong here
That's now how inheritance works. Method chaining goes up the class hierarchy, now down.
Static methods are connected to the class. If you override a static method in a subclass, and want to invoke the subclass' version, you must reference the subclass explicitly.
Interfaces have no implementation. Even if the language allowed the type of call you're making, nothing would happen. AJAXDispatcher::dispatch() has no body.
You're going to have to re-think your strategy here.
In C++, I code this way:
//foo.h
class cBar
{
void foobar();
}
//foo.cpp
void cBar::foobar()
{
//Code
}
I tried to do this on PHP but the parser would complain. PHP's documentation also doesn't help. Can this be done in PHP?
No. You need to including all your function definitions inside the class block. If defining your functions in a separate structure makes you feel better you could use an interface.
interface iBar
{
function foobar();
}
class cBar implements iBar
{
function foobar()
{
//Code
}
}
I'd suggest just getting used to coding in a new way. It's easy to code consistantly within a single language, but I think you are fighting a loosing battle if you want to do the same across languages.
You can't really do this in the same manner.
You can use class abstraction and interfaces, though. The main difference between the two is that and interface does not allow you to specify the function body, where (not abstract) methods in an abstract object can hold all kinds of default behaviour.
Abstraction:
abstract class cBar
{
// MUST be extended
abstract protected function foobar();
// MAY be extended
protected function someMethod()
{
// do stuff
}
}
class cBarExtender extends cBar
{
protected function foobar()
{
// do stuff
}
}
Interfacing:
interface cBar
{
// MUST be implemented
protected function foobar();
}
class cBarImplementation implements cBar
{
protected function foobar()
{
// do stuff
}
}
The language doesn't really provide this feature but if you really want it, you can install the ClassKit extension which will let you do some dynamic class modifications at run-time.