I have a question, can a method from an interface get additional parameters during the implementation like an abstract method? for example:
<?php
interface Figures {
public function setColor($color);
}
class Circle implements Figures {
public function setColor($color, $additional_parameter, ...) {
}
}
?>
No, it will give you an error like this
Fatal error: Declaration of Circle::setColor() must be compatible with Figures::setColor($color)
You can do this as long as you make the additional parameters optional:
public function setColor($color, $additional_parameter = "defaultvalue", $another_parameter = null) { ...
Still it's not the best idea as it will be hard to use your code in a predictable way, as sometimes your argument will be just ignored. It's also bad practice not to follow the interface definition strictly.
Re your question: no.
An interface is supposed to provide a "contract" that all children must adhere to. As such, it might not be a good idea to break that contract by doing extra things anyway.
An alternative option is to provide a public setter for the additional parameters, then access them by properties within setColor():
interface Figures {
public function setColor($color);
}
class Circle implements Figures {
protected $_additionalParameter;
public function setColor($color) {
echo $this->_additionalParameter . ' - not passed in any more';
}
public function setAdditionalParameter($blah = '')
{
$this->_additionalParameter = $blah;
return $this;
}
}
And used like so:
// you implement stuff
$circle = new Circle;
$circle->setAdditionalParameter('blah')
->setColor('color');
// blah - not passed in any more
If you have lots of additional parameters you might find it tidier to use the magic method __set() to cover all your bases instead of loading up your classes with lots of them.
Related
In an application I'm building there's a CLI entry point class:
class CLIEntryPoint {
protected $factory;
public function __construct(ApplicationObjectFactoryInterface $factory) {
$this->factory = $factory;
}
public function run(...$args) {
$choice = $args[1];
$appObject = $this->factory->makeApplicationObject($choice);
$appObject->doApplicationRelatedStuff();
}
}
This entry point is created using Dependency Injection in my "front controller" script and it receives an ApplicationObjectFactoryInterface implementation (actually the current implementation of ApplicationObjectFactoryInterface is injected by the DI container, which in turn reads it from its configuration file, but that's not the point).
The current implementation of ApplicationObjectFactoryInterface also uses DI and depends on other factories which help it building the resulting application object:
class CurrentImplementationOfApplicationObjectFactory implements ApplicationObjectFactoryInterface {
protected $someComponentFactory;
protected $anotherComponentFactory;
public function __construct(SomeComponentFactoryInterface $someComponentFactory, AnotherComponentFactoryInterface $anotherComponentFactory) {
$this->someComponentFactory = $someComponentFactory;
$this->anotherComponentFactory = $anotherComponentFactory;
}
/**
* Interface's method
*
* #return ApplicationObjectInterface
*/
public function makeApplicationObject($choice) {
$component = $this->someComponentFactory->makeSomeComponent();
$anotherComponent = $this->anotherComponent->makeAnotherComponent();
switch ($choice) {
case 1:
return new CurrentImplementationOfApplicationObject1($component, $anotherComponent);
case 2:
return new CurrentImplementationOfApplicationObject2($component, $anotherComponent);
default:
return new DefaultImplementationOfApplicationObject($component, $anotherComponent);
}
}
}
Here CurrentImplementationOfApplicationObject1, CurrentImplementationOfApplicationObject2 and DefaultImplementationOfApplicationObject all implement the ApplicationObjectInterface interface and therefore they all have the doApplicationRelatedStuff method.
I would like to know whether it's good practice or not to write code like I did and if not how can I improve it.
Basically here I am creating a component which depends on other components in order to function properly using a factory which in turn needs inner factories to build the component which implements the ApplicationObjectInterface interface.
Is it considered good practice?
Thanks for the attention, as always!
EDIT: I looked at the article of Steven and tried to refactor CLIEntryPoint. The only problem now seems to be how to pass the $choice parameter to the factory which now is inside of the proxy when the run() method is called. Is this code structure better than the one I posted above? Of course, SomeComponentFactoryInterface and AnotherComponentFactoryInterface should follow the same behaviour (the factory that uses them should not use them directly, but through two proxies which implement, in order, SomeComponentInterface and AnotherComponentInterface). I hope I get it right, anyway, here is the code:
class CLIEntryPoint {
protected $applicationObject;
public function __construct(ApplicationObjectInterface $applicationObject) {
$this->applicationObject = $applicationObject;
}
public function run(...$args) {
$choice = $args[1]; // How do I deal with different choices when I am using a Proxy? I should have different application objects depending on input.
$this->applicationObject->doApplicationRelatedStuff();
}
}
interface ApplicationObjectInterface {
public function doApplicationRelatedStuff();
}
class ApplicationObjectProxy implements ApplicationObjectInterface {
protected $applicationObjectFactory;
protected $applicationObjectImplementation = NULL;
public function __construct(ApplicationObjectFactoryInterface $factory) {
$this->applicationObjectFactory = $factory;
}
public function __call($method, $args) {
// Calling interface's
$implementation = $this->getImplementation();
$methodOfInterfaceToCall = preg_replace('/Proxy$/', '', $method);
return $implementation->{$methodOfInterfaceToCall}(...$args);
}
/**
* Laxy loading method.
*/
protected function getImplementation() {
if (is_null($this->applicationObjectImplementation)) {
$this->applicationObjectImplementation = $this->applicationObjectFactory->makeApplicationObject(); // Choice should go here somehow...
}
return $this->applicationObjectImplementation;
}
public function doApplicationRelatedStuff() {
// This will call the PHP's magic `__call` method, which in turn will forward the call to the application object's
// implementation returned by the factory.
return $this->doApplicationRelatedStuffProxy();
}
}
Actually yes, this is a pattern called the Abstract Factory Pattern. So an example that I used to present it in front of my class during my undergrad:
So if you are building a video game first person shooter, you might want to create three concrete factories like:
FlyingMonsterFactory
SwimmingMonsterFactory
WalkingMonsterFactory.
All these factories would implement an abstract MonsterFactory.
With this, you can have your video game create a level in which you want waves of the same type of monsters, so you can have a randomWaveMonsterGenerator method return a MonsterFactory which might have returned a concrete SwimmingMonsterFactory. So then you will have a wave of SwimmingMonster(s) generated by the SwimmingMonsterFactory.
So answer your description more directly, looking at your code above, you asked the question on choice for Dependency Injection. With Dependency Injection, I believe for this type of pattern, you will have to inject every concrete class before your code even attempts to get the implementation class.
So for example:
Your code above says the run method gives an argument called
choice.
With this choice, you will have to use it as a parameter into a getImplementation method.
All the concrete objects that the getImplementation method that rely upon Dependency
Injection have to be created BEFORE you call the getImplementation method.
But since you don't know which implementation class will be called, I believe you have to inject ALL the implementation classes before hand.
Then you can use the choice variable as a parameter to get the correct implemented factory class.
Hope this helps!
I am fairly new to PHP OOP and I am getting an error.
objectForm::addMessage() must be compatible with that of objectAbstractForm::addMessage() in /www/form/Form.php on line xx
I have seen this a few times where the method parameters are like $var1, $var2 = false (or null) and for whatever reason I get "must be compatible with that of X::Y()"
public function addMessage($message, $messageType = 'info')
{
if (!in_array($message, $this->_messages)) {
if ('info' == $messageType) {
$this->_messages[] = $message;
} else {
$this->_errorMessages[] = $message;
}
}
}
Since I'm fairly new at OOP, I cannot figure out a better way for this.
Edit: In the parent have for example,
abstract class objectAbstractForm {
abstract protected function addMessage($message, $messageType);
}
What is a better way to do this? I am using PHP 5.2.17
The issue is that you've made the 2nd argument optional in the child class but it's required in the parent class. If you want an optional argument, you'll need to make it optional in the parent class as well.
I imagine your class is extending another (from the error message it's extending objectForm in /www/form/Form.php), the method signature for the objectAbstractForm::addMessage() (your method posted here) must be the same as objectForm::addMessage().
For example:
class A {
public function test($a, $b, $c=null) {
// code
}
}
class B extends A {
public function test($a, $b, $c=null) {
// code
}
}
class C extends A {
public function test($a, $b=null) {
// code
}
}
Class C will generate your error, the signature of the method C::test() is different from the signature in the method A::test(), whereas B::test() will be accept, because its signature is the same as A::test().
I'll be more than happy to make my answer more specific to your question but you'll need to post the method signature for objectForm::addMessage() and the class signature for both objectAbstractForm and Form
EDIT: I had my guesses of your classes the other way around, but the principle is the same, you cannot have a mismatch of parameters in PHP 5.2. You will need to edit the signature for whichever you prefer.
Alternatively, you can upgrade to PHP 5.3 or higher and this won't nag you.
HTH
P.S.: I'm not sure if I'm using the right terminology when I say "method signature", but if I'm wrong, feel free to correct me :)
Here's the objective. I have a PHP class and there are one or two of its methods that I would like to override with my own. As I understand OOP (in PHP and in general) I could write a child class that extends it and overrides the functionality of the methods in question.
However, I was wondering if this is the best way of achieving this task and if this is a proper use for child classes or if there is something better in PHP for what I'm trying to do.
Yes, that is the best way to do it. The idea of extending a class is to provide extra or more specific functionality.
yes. this exactly what you use inheritance for.
A good principle though, is make sure your new inheriting class "is-a" base class.
Like Human is-a Mammal. Don't do Alien extends Human just because Alien does a lot of stuff Humans do.
So, are you asking if overriding methods (which requires extending the superclass) is the best way to override methods? Yes.
That is the most important use of subclasses. In fact, polymorphism is at the heart of OOP. The other use is to provide new properties/methods, but that usually won't be enough.
class oldClass {
public function methodToOverride() {
echo 'oh hai';
}
}
class childClass extends oldClass {
public function methodToOverride($arg, $arg2) {
// your custom code
echo 'hai world ' . $arg . ' ' . $arg2;
// if you need to still call the parent class
parent::methodToOverride();
}
}
$child = new childClass();
$child->methodToOverride('nom', 'nom');
Sounds like you're on the right track.
For the methods you want to override, you'd probably want to:
make sure you're not changing the intent of the method
know whether you have to call the base class's method within, and when
The only other way, would be to create a generic "superclass"...
class SuperClass {
protected $obj = null;
protected $overrides = array();
public function __construct($obj) {
if (!is_object($obj)) {
throw new InvalidArgumentException('Argument is not an object');
}
$this->obj = $obj;
}
public function __call($method, $args) {
$method = strtolower($method);
if (isset($this->overrides[$method])) {
array_unshift($args, $this);
return call_user_func_array($this->overrides[$method], $args);
} elseif (is_callable(array($this->obj, $method))) {
return call_user_func_array(array($this->obj, $method), $args);
} else {
throw new BadMethodCallException('Invalid Method Called');
}
}
public function __get($var) {
return isset($this->obj->$var) ? $this->obj->$var : null;
}
public function __set($var, $value) {
$this->obj->$var = $value;
}
public function addOverride($method, $callback) {
$this->overrides[strtolower($method)] = $callback;
}
}
It's not always the best solution, but it's possible that some situations exist to use something like that. It will let you "add" and "override" methods to any object at run time.
The better generic solution is to simply extend the class in a child class... But the above "superclass" does have some uses...
Another route I haven't seen mentioned here is to question whether it wouldn't be better to extract an abstract class and have the two classes extend that. Of course you would need to be able to alter the code of the first class for that (e.i. if the class came from an open source library you might refrain from changing the code).
you are on the right track
I've got a bunch of functions that I want to move into a class. They're currently split into a couple of fairly long files. I'd prefer not to have one 2500 line file, but as far as I can tell, you can't use include to split a class up into multiple files. In theory, I could group the functions in different classes, but they're closely related enough that I feel like they belong together, and splitting them will reduce some of the utility that I'm hoping to get from moving away from a procedural approach (with shared properties, rather than a bunch of parameters that are in nearly every function).
I know this is a bit vague, but any suggestions/pointers? If it matters, this is for a prototype, so ease of code management takes precedence over security and performance.
UPDATE: Let me see if I can remove some of the vagueness:
This class/set of functions outputs the html for a complex form. There are many different sections and variations within each section, depending on about 5 or 6 parameters, which are currently passed into the functions. I was hoping to define the parameters once as properties of the class and then have access to them from within all of the section-creation methods. If I use sub-classes, the values of those properties won't be initialized properly, hence the desire for one class. (Hmm... unless I define them as static. I may have just answered my own question. I'll have to look to see if there's any reason that wouldn't work.)
I've currently got a mess of functions like:
get_section_A ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
if ($this->type == 'foo') { }
else ($this->type == 'foo') { }
}
So I was initially imagining something like:
class MyForm {
public $type; // or maybe they'd be private or
public $mode; // I'd use getters and setters
public $read_only; // let's not get distracted by that :)
public $values_array;
// etc.
function __constructor ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
$this->type = $type;
// etc.
}
function get_sections () {
$result = $this->get_section_A();
$result .= $this->get_section_B();
$result .= $this->get_section_C();
}
function get_section_A() {
if ($this->type == 'foo') { }
else { }
}
function get_section_B() {}
function get_section_C() {}
// etc. for 2500 lines
}
Now I'm thinking something like:
// container class file
class MyForm {
static $type
static $mode
static $read_only
static $values_array
// etc.
function __constructor ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
MyForm::$type = $type;
// etc.
}
function get_sections () {
$result = new SectionA();
$result .= new SectionB();
$result .= new SectionC();
}
}
// section A file
class SectionA extends MyForm {
function __constructor() {
if (MyForm::$type == 'foo') { }
else { }
}
function __toString() {
// return string representation of section
}
}
// etc.
Or probably I need an abstract class of FormSection where the properties live.
Any other ideas/approaches?
I'd split them up into as many classes as you want (or as many that make sense) and then define an autoloader to obviate inclusion headaches.
EDIT
Ok, after seeing more of your code - I think you're approaching subclasses wrong. You have lots of if statements against $type, which signals to me that that is what the polymorphism should be based on.
abstract class MyForm
{
protected
$mode
, $read_only
, $values
;
public function __construct( $mode, $read_only=false, array $values = array() )
{
$this->mode = $mode;
$this->read_only = (boolean)$read_only;
$this->values = $values;
}
abstract function get_section_A();
abstract function get_section_B();
abstract function get_section_C();
// final only if you don't want subclasses to override
final public function get_sections()
{
return $this->get_section_A()
. $this->get_section_B()
. $this->get_section_C()
;
}
}
class FooForm extends MyForm
{
public function get_section_A()
{
// whatever
}
public function get_section_B()
{
// whatever
}
public function get_section_C()
{
// whatever
}
}
Usually I do something like this:
class one
{
public function __get($key)
{
// require __DIR__ / $key . php
// instanciate the sub class
}
public function mainMethod()
{
}
}
class one_subOne extends one
{
public function otherMethod()
{
}
}
class one_subTwo extends one
{
public function anotherMethod()
{
}
}
$one->mainMethod();
$one->subOne->otherMethod();
$one->subTwo->anotherMethod();
As far as building the view is concerned, you might like to try the CompositeView pattern.
Here's a small example of how it could look in PHP. Pretend, for the sake of this example, that View::$html is encapsulated in a Template class that can load html from disk and allows you to inject variables, handles output escaping, etc.
interface IView {
public function display();
}
class View implements IView {
public $html = '';
public function display() {
echo $this->html;
}
}
class CompositeView implements IView {
private $views;
public function addPartial(IView $view) {
$this->views[] = $view;
}
public function display() {
foreach ($this->views as $view) {
$view->display();
}
}
}
The reason for the IView interface is to allow you to build composite views with other composite views.
So now consider a form with three parts: header, body and footer.
class HeaderView extends View {
public function __construct() {
$this->html .= "<h1>Hi</h1>\n";
}
}
class BodyView extends View {
public function __construct() {
$this->html .= "<p>Hi there.</p>\n";
}
}
class FooterView extends View {
public function __construct() {
$this->html .= "<h3>© 2012</h3>\n";
}
}
(Again, you wouldn't just write HTML into that public variable and handle output escaping yourself. You'd likely reference a template filename and register your data via the template's interface.)
Then, to put it all together you would go:
$view = new CompositeView();
// here you would make decisions about which pieces to include, based
// on your business logic. see note below.
$view->addPartial(new HeaderView());
$view->addPartial(new BodyView());
$view->addPartial(new FooterView());
$view->display();
So now your views can be composed and the fragments reused, but you can easily make a mess with the code that builds them, especially if you have a lot of conditions and many different possible outcomes (which it sounds like you do.) In that case, the Strategy pattern will probably be of some help.
If you haven't already read UncleBob's SOLID article, do it before anything else! At least the Single Responsibility Principle. I would also recommend reading Refactoring to Patterns by Joshua Kerievsky at some point.
If you want to do OOP, separate the concerns and encapsulate them into appropriate classes. Combine them either by extending them or by composition or better aggregation. Remove any duplicate code. Dont repeat yourself.
In your case, separate the stuff that is about any Form from the stuff that is about your specific form. The code that can be used for any Form is the code you want to place into a generic Form class. You can reuse this in later projects. For an example of a very complex Form class, check out Zend_Form.
Anything in your code related to the/a specific form gets into a class of it's own that extends the generic form. Assuming from the type property given in your code, you might end up with multiple special purpose form classes (instead of one-type-fits-all-form), which will likely eliminate the complexity from the getSection methods and make your code a lot easier to maintain because you can concentrate on what a specific type of form is supposed to look like and do.
Lastly, if you got code in there that fetches data for the form from within the form or is otherwise not directly related to form building, remove it and make it into a separate class. Remember, you want to separate concerns and your form classes' concern is to build a form, not get it's data or something. Data is something you will want to pass to the form through the constructor or a dedicated setter.
They are all in different files, which means that they were different enough to group by file. Just take the same logic when building them into classes. I have a Page object that deals with building the page. Technically the HTML for my page header is part of the page, but I separate it into a Page_HTML class for maintaining my sanity and not creating gigantic classes.
Also, I tend to make the sub_classes, like Page_HTML in this case, static, instead of instantiating it. That way I can access the $this variables in the Page class, but still group it into another class.
class Page
{
function buildPage($content)
{
$content = Page_HTML::getHeader() . $content;
}
}
class Page_HTML
{
function getHeader()
{
}
}
This class/set of functions outputs
the html for a complex form.
Why not remove PHP from the equation? It seems you're using PHP to organize views which can be done easily with the filesystem. Just write the views in HTML with as little PHP as possible. Then use PHP to map requests to views. I'm assuming you're processing forms with PHP, and you could continue to do so. However, your classes will become much smaller because they're only accepting, verifying and presumably saving input.
Trying to figure out whether PHP supports features like method overloading, inheritance, and polymorphism, I found out:
it does not support method overloading
it does support inheritance
but I am unsure about polymorphism. I found this Googling the Internet:
I should note that in PHP the
polymorphism isn't quite the way it
should be. I mean that it does work,
but since we have a weak datatype, its
not correct.
So is it really polymorphism?
Edit
Just can't quite place a definite YES or NO next to PHP supports polymorphism. I would be loath to state: "PHP does not support polymorphism", when in reality it does. Or vice-versa.
class Animal {
var $name;
function __construct($name) {
$this->name = $name;
}
}
class Dog extends Animal {
function speak() {
return "Woof, woof!";
}
}
class Cat extends Animal {
function speak() {
return "Meow...";
}
}
$animals = array(new Dog('Skip'), new Cat('Snowball'));
foreach($animals as $animal) {
print $animal->name . " says: " . $animal->speak() . '<br>';
}
You can label it all you want, but that looks like polymorphism to me.
although PHP does not support method overloading the way you have experienced in other languages, say Java. but you CAN have method overloading in PHP, but the definition method is different.
if you want to have different functionality for a given method, with different set of parameters in PHP, you can do something like this:
class myClass {
public function overloadedMethod() {
// func_num_args() is a build-in function that returns an Integer.
// the number of parameters passed to the method.
if ( func_num_args() > 1 ) {
$param1 = func_get_arg(0);
$param2 = func_get_arg(1);
$this->_overloadedMethodImplementation2($param1,$param2)
} else {
$param1 = func_get_arg(0);
$this->_overloadedMethodImplementation1($param1)
}
}
protected function _overloadedMethodImplementation1($param1) {
// code 1
}
protected function _overloadedMethodImplementation2($param1,$param2) {
// code 2
}
}
there could be cleaner implementation, but this is just a sample.
PHP supports inheritance and interfaces. so you can have polymorphism using them. you can have an interface like this:
// file: MyBackupInterface.php
interface MyBackupInterface {
// saves the data on a reliable storage
public function saveData();
public function setData();
}
// file: myBackupAbstract.php
require_once 'MyBackupInterface.php';
class MyBackupAbstract implements MyBackupInterface {
protected $_data;
public function setData($data) {
$this->_data= $data;
}
// there is no abstract modifier in PHP. so le'ts avoid this class to be used in other ways
public function __construct() {
throw new Exception('this class is abstract. you can not instantiate it');
}
}
// file: BackupToDisk.php
require_once 'MyBackupAbstract.php';
class BackupToDisk extends MyBackupAbstract {
protected $_savePath;
// implement other methods ...
public function saveData() {
// file_put_contents() is a built-in function to save a string into a file.
file_put_contents($this->_savePath, $this->_data);
}
}
// file: BackupToWebService.php
require_once 'MyBackupAbstract.php';
class BackupToWebService extends MyBackupAbstract {
protected $_webService;
// implement other methods ...
public function saveData() {
// suppose sendData() is implemented in the class
$this->sendData($this->_data);
}
}
now in your application, you might use it like this:
// file: saveMyData.php
// some code to populate $myData
$backupSolutions = array( new BackupToDisk('/tmp/backup') , new BackupToWebService('webserviceURL') );
foreach ( $backupSolutions as $bs ) {
$bs->setData($myData);
$bs->saveData();
}
you are right, PHP is not strong typed language, we never mentioned that any of your $backupSolutions would be a 'MyBackupAbstract' or 'MyBackupInterface', but that would not stop us from having the nature of polymorphism which is different functionality over using the same methods.
PHP has class-based polymorphism, but lacks a formal mechanism for implementing argument-based polymorphism.
Class-based polymorphism means that you can think in terms of a base class, and have the methods being called depend on the final class. For instance, if you have an array of objects of various classes such as Triangle and Circle, and each of these classes extends the same class Shape, you can regard your array as merely a collection of shapes. You can loop through the shapes and call each shape's getArea() method. Polymorphism is the phenomenon whereby the getArea() method being called depends on the class of the object. If your shape is a Triangle, Triangle::getArea() gets called, if a Circle, then Circle::getArea() gets called--even though your code doesn't distinguish between a Circle and a Triangle but regards each object as merely a Shape. The same line of code results in a different block of code being executed, depending on the object's class.
Argument-based polymorphism is a feature of some strongly-typed languages, wherein multiple methods of the same name can be defined in a single class, provided that they have different parameters; then which method is called depends on the arguments provided. You can emulate argument-based polymorphism in weakly-typed languages like PHP by manually considering your argument types within your method. This is what jQuery does in order to implement a polymorphic API despite JavaScript's lack of native argument-based polymorphism.
So if by "supports polymorphism" you mean specifically that it provides a formal mechanism for implementing argument-based polymorphism, the answer is no. For any broader interpretation, the answer is yes. It stands to reason that the phenomenon of class-based polymorphism occurs in every Object-Oriented language; and it makes no sense for a language that performs implicit type conversion to implement argument-based polymorphism.
__call() and __callStatic() should support method overloading. More on this is available in the manual. Or what exactly are you after?
UPDATE: I just noticed the other replies.
For another way to overload a method, consider the following:
<?php
public function foo()
{
$args = func_get_arg();
}
Certainly not pretty, but it allows you to do virtually whatever you want.
You can still override methods, just not overload them. Overloading (in C++) is where you use the same method name for multiple methods, differing only in number and types of parameters. This would be hard in PHP since it's weak-typed.
Overriding is where the sub-class replaces a method in the base class. Which is really the basis for polymorphism, and you can do that in PHP.
Some call this duck typing.
PHP allows for polymorphic code that would generate an compile error in other languages. A simple illustrates this. First C++ code that generates an expected compile error:
class Base {};
class CommonDerivedBase {
public:
// The "= 0" makes the method and class abstract
// virtual means polymorphic method
virtual whoami() = 0;
};
class DerivedBase : public CommonDerivedBase {
public:
void whoami() { cout << "I am DerivedBase \n"; }
};
class Derived1 : public CommonDerivedBase {
public:
void whoami() { cout << "I am Derived1\n"; }
};
class Derived2 : public CommonDerivedBase {
public:
void whoami() { cout << "I am Derived2\n"; }
};
/* This will not compile */
void test_error(Base& db)
{
db.whoami();
}
The C++ compiler will issue this error message for the line db.whoami()
error: no member named 'whoami' in 'Base'
because Base does not have a method called whoami(). However, the analogous PHP code does not find such errors until run time.
class Base {}
abstract class DerivedCommonBase {
abstract function whoami();
}
class Derived1 extends DerivedCommonBase {
public function whoami() { echo "I am Derived1\n"; }
}
class Derived2 extends DerivedCommonBase {
public function whoami() { echo "I am Derived2\n"; }
}
/* In PHP, test(Base $b) does not give a runtime error, as long as the object
* passed at run time derives from Base and implements whoami().
*/
function test(Base $b)
{
$b->whoami();
}
$b = new Base();
$d1 = new Derived1();
$d2 = new Derived2();
$a = array();
$a[] = $d1;
$a[] = $d2;
foreach($a as $x) {
echo test($x);
}
test($d1);
test($d2);
test($b); //<-- A run time error will result.
The foreach loop works with the output
I am Derived1
I am Derived2
Not until you call test($b) and pass an instance of Base will your get a run time error. So after the foreach, the output will be
I am Derived1
I am Derived2
PHP Fatal error: Call to undefined method Base::whoami() in
home/kurt/public_html/spl/observer/test.php on line 22
About the only thing you can do to make the PHP safer would be to add a run time check
to test if $b is an instance of the class you intended.
function test(Base $b)
{
if ($b instanceof DerivedCommonBase) {
$b->whoami();
}
}
But the whole point of polymorphism is to eliminate such run time checks.
Polymorphism can be implemented in the following methods:
method overriding - normal pretty was as above
method overloading
You can create an illusion of method overloading by the magic method __call():
class Poly {
function __call($method, $arguments) {
if ($method == 'edit') {
if (count($arguments) == 1) {
return call_user_func_array(array($this,'edit1'), $arguments);
} else if (count($arguments) == 2) {
return call_user_func_array(array($this,'edit2'), $arguments);
}
}
}
function edit1($x) {
echo "edit with (1) parameter";
}
function edit2($x, $y) {
echo "edit with (2) parameter";
}
}
$profile = new Poly();
$profile->edit(1);
$profile->edit(1,2);
Expln:
1) Here we are utilizing the power of __call() of listening calls of
non-available methods and
2) after knowing it who had called with their inputs diverting them to desired
method
In php, we are actually working under the hood to give the desired behaviour and giving the feeling of method overloading
For what I’ve seen here php do not support polymorphism, nor overloading methods. You can hack your way to actually get close to both of these oop functionalities, but they are far from the original purpose of it. Many of the examples here either are extending a class or creating a hack to emuluate polymorphism.