PHP - Mixing object Injection & inheritance - php

This is a follow up question on the following answer : Parent Object in php
class A {
protected function doSomeStuff(){
echo 'a method that all children will need to call';
}
}
class B {
protected $_parent;
public function __construct($parent) {
$this->_parent = $parent;
}
public function doSomeLocalStuff() {
$this->_parent->doSomeStuff(); // Fatal Error
}
}
$a = new A(); // will be used for other children as well.
$b = new B($a);
$b->doSomeLocalStuff();
In the above code, parent object Injection was used, allowing class B to be initialized using a specific instance of class A, but class B wont be able to access class A protected properties or methods (e.g., doSomeStuff()).
But by mixing the above with inheritance, we get the best of both worlds :)
class B extends A {
protected $_parent;
public function __construct($parent) {
$this->_parent = $parent;
}
public function doSomeLocalStuff() {
$this->_parent->doSomeStuff(); // Works :)
}
}
So, is this acceptable ? .. any drawbacks ?
P.S: I'm trying to implement a non-static factory pattern.
Clarification
Consider this, I'm trying to design a class which will be used for calling an external API. We've over 400 different calls, divided into 10 categories (billing, customers, products ... ).
All the 400 calls shares the same parent-url, username/password and some other common properties.
So, instead of putting the 400 method in one big class, I decided to divide them into 10 classes, with a parent class handling common functions (e.g., authentication, url construction, web call ... ), then created a factory pattern, where I can load only needed classes/categories on run-time.
Something like :
$apiCall = new parentPlusFactory();
//contains common methods and a mechanism to load sub-classes
$apiCall->setAPIuserName("user");
$apiCall->setAPIpassword("pass");
$apiCall->useClass('customers')->doSomeCustomerStuff();
$apiCall->useClass('products')->doSomeProductStuff();
That's why I need to share the same parent class instance.

There is no friend keyword in PHP, like in C++. You could check this discussion for a way to implement friend classes.
But do you really need that function to be declared protected?

In general you should favor composition over inheritance. To me your use case sounds like B should not be extending A at all, but instead you should have two separate classes.
Now, PHP 5.4 will have "horizontal reuse", also known as "traits", where it will be possible to "include" a trait into your class.
trait A
{
public function doSomeStuff()
{
echo 'doing some stuff';
}
}
class B
{
use A;
public function doSomeLocalStuff()
{
$this->doSomeStuff();
}
}
class C
{
use A;
public function doSomeLocalStuff()
{
echo 'Doing something completely different here';
}
}
See also PHP manual: traits and PHP 5.4 beta1 released.

Related

Use parents child method in other child class (same parent)

I have some issues with OOP. I just started OOP in php and i have some issues.
So i have a question for you, maybe you'll help me.
I have multiple classes (in this case 3)
<?php
//FILE class.NB.php
class NB { //databse manipulations, curls
public $db;
function __construct($db) {
$this->db = $db;
}
public function LoginNB () {
//something here
$this->db->query("UPDATE logins SET login_time = %u", time());
}
}
//FILE class.fn.php
class FN extends NB {
public function deposits () {
$this->LoginNB();
return $this->db->query("SELECT * FROM deposits");
}
public function getUserWihdrawsCompared() {
// AND HERE I WOULD LIKE TO USE the DR's ::usersWithdraws
$users = $this->usersWithdraws();
}
}
//FILE class.dr.php
class DR extends NB {
public function withdraws () {
$this->LoginNB();
return $this->db->query("SELECT * FROM withdraws");
}
public function usersWithdraws() {
$a = $this->db->query("SELECT * FROM user_withdraws");
/*code here*/
return $final_array;
}
public function compare_withdraws_deposits () {
// AND HERE I WOULD LIKE TO USE the FN's ::deposits
$deposit_list = $this->deposits();
/* code here */
return $final_array;
}
}
?>
So my question is, how is possible to use everything in everywhere.
I saw something with traits but i'm not sure, how to use and what exactly to use.
My problems is what i want to user parent's child method in other child with same parent.
But in the end, i would like to use only the parent class for "runing" implementing in other classes if it's possible.
Like:
$NB = new NB($db);
$result = $NB->ShowResults();
Problem: ShowResults() should use both child's methods and child methods used in ShowResults() some times use methods from other child class.
Maybe it's impossible but i would appreciate if you could help me. (even with a confirmation that is not possible)
Thank you.
I think you haven't fully grasped what we mean by "parent" and "child" in OOP, and why they're useful. The purpose of inheritance is not to grant access to the methods of one class in another, or to automatically run multiple implementations of the same thing. Instead, the purpose is to allow code outside the classes to call one of the implementations without needing to know which one.
So, if I have an instance of class NB, I know I can call LoginNB on it. If what I'm passed is actually an instance of class FN, that will still work; class FN will either inherit that method, or reimplement it a different way, but with the same external signature.
However, class NB doesn't know anything about what classes inherit from it, any more than a function knows where else it is called from; the relationship only goes one way.

PHP Class dynamically extending in runtime

Is it possible to dynamically extend a class object in PHP? And what would be the most elegant way of doing this?
Some example code for further explanation:
class BasicClass {
private $variable;
public function BasicFunction() {
// do something
$this->variable = 10;
}
}
class ExtendedClass extends BasicClass {
public function ExtendedFunction() {
// do something else with basic class variable
return $this->variable/2;
}
}
$A = new BasicClass();
If(condition for extension){
// A should be of class ExtendedClass
// and the current class variables should be kept
// ... insert the magic code here ...
// afterwards we would be able to use the ExtendedFunction with the original variables of the object
$A->ExtendedFunction();
}
One way of tackling this would be creating a new object of ExtendedClass and copying all the variables from the old object. But can this be done more elegantly?
Yes. It is possible. One way to do it would be using anonymous classes or simply overwriting the class itself(in your case $A) but that implies a little more logic and it's not as clean, so I won't get into it.
NOTE: Support for anonymous classes was added in PHP 7.
Using your example above we can compose the following code(I changed the visibility of the property in order to be able to use it in the extended class. I'd suggest you add a getter rather than changing the visibility).
class BasicClass {
public $variable;
public function BasicFunction() {
// do something
$this->variable = 10;
}
}
class ExtendedClass extends BasicClass {
public function ExtendedFunction() {
// do something else with basic class variable
return $this->variable / 2;
}
}
$A = new BasicClass();
if (TRUE) {
// A should be of class ExtendedClass
$A = new class extends ExtendedClass {
};
$A->ExtendedFunction();
}
Do note that this will overwrite $A. You'll still have all the available methods in it since inheritance is not lost by doing this.
Obviously whichever approach you take won't be the cleanest way you can do this.
My answer stands, but if you were to edit your question and provide more details on what it is you want to actually achieve by doing this perhaps a different approach is more suitable.
You can also achieve some magic using eval and possibly Reflection, but they're so magically magic I refuse to write the answer since it promotes such bad practices.

PHP get child class methods

Is it possible in PHP to get the methods of an extended child class in a method declared in the parent class?
Here is a simple (maybe stupid) example:
<?php
class Vehicle{
protected function moveForward(){
// go ahead...
}// moveForward
public function getWhatCanIDo(){
$actions = get_class_methods($this);
return 'I can '.implode(', ', $actions).'<br/>';
}// getWhatCanIDo
}
class Car extends Vehicle{
protected function honk(){
// honk...
}// honk
protected function turnHeadlightsOn(){
// turn headlights on...
}// turnHeadlightsOn
protected function stopEngine(){
// stop the engine
}// stopEngine
}
class Submarine extends Vehicle{
protected function submerge(){
// sink...
}// submerge
protected function ping(){
// ping...
}// ping
protected function fireTorpedos(){
// DESTROY!!!
}// fireTorpedos
protected function stopEngine(){
// stop the engine
}// stopEngine
}
$volvo = new Car();
$uboat = new Submarine();
echo $volvo->getWhatCanIDo();
echo $uboat->getWhatCanIDo();
?>
The output what I expect is:
I can moveForward, getWhatCanIDo, honk, turnHeadlightsOn, stopEngine
I can moveForward, getWhatCanIDo, submerge, ping, fireTorpedos, stopEngine
But instead It returns the the methos of the Vehicle class only, without the methods implemented in the extended class:
I can moveForward, getWhatCanIDo
I can moveForward, getWhatCanIDo
How could I get the extanded class methods?
Additional Infos:
I have to solve this in PHP 5.2.14
The extended classes will have different numbers of methods with different method names so making Vehicle an abstract class wont help, because e.g.: I dont want Submarine to have honk method.
I know I could make the getWhatCanIDo() an abstract method, but I'd like to implement this method "centrally" in the parent class, I dont want to oblige developers to write getWhatCanIDo() method for every extended class (In the future others may join or continue this project, and Its more failsafe to not let them implement this method again and again especially when the method does exactly the same thing.)
You should declare class Vehicle abstract, because it does not really exist and the real vehicles implement it.
Then put whatCanIDo in Car and in Submarine, because you don't ask the vehicle what it can do, you ask the car.
class Car extends Vehicle{
public function getWhatCanIDo(){
$actions = get_class_methods($this);
return 'I can '.implode(', ', $actions).'<br/>';
}// getWhatCanIDo
}
Update:
A yet different approach is to use the standard PHP library ReflectionClass:
$class = new ReflectionClass('Vehicle');
$methods = $class->getMethods();
You need to overload the getWhatCanIDo() function in the Car & Submarine classes. You get the output because the function is executed in the Vehicle class.
Overloading the method causes it to be executed in either the Car or Submarine class.
You could also try get_class_methods(); More at http://www.php.net/manual/en/function.get-class-methods.php
This code is not tested, please, let me know if it works.
class MyBaseClass {
//...
public function getMethods($className) {
return get_class_methods($className);
}
public static function getMethods($myObject) {
return $myObject->getMethods(get_class($myObject));
}
//...
}
class MyInheritedClass {
//...
}
$myBaseObject = new MyBaseClass(/*...*/);
$myInheritedObject = new MyInheritedClass(/*...*/);
echo var_dump(MyBaseClass::getMethods($myBaseObject));
echo var_dump(MyBaseClass::getMethods($myInheritedObject));
Inheritance is not proper tool here. You should use composition. Example:
Have separate objects Runner, Swimmer, WorkWithEngine, Submerge. All off them implements interface with getWhatCanIDo() method.
Create your new Vehiclas by composing them from Types from point one. This object implements interface with getWhatCanIDo() method as well.
$submarine = new Submarine();
$submarine->addAblility(new Swimmer());
$submarine->addAblility(new WorkWithEngine());
$submarine->addAblility(new Submerge());
$submarine->whatCanIDo();
In any case do not use magic like get_class_methods those are constructs for frameworks creators it is not stuff for coding business logic.

OOP/PHP5: Calling Class A from Class B - or, Making the horse jump

Say you have two classes, A and B. Is it possible to instantiate both classes once and then let class B call methods in class A, and vice versa?
It can be done using double colon (::) ... ... but then the method becomes static - is that a disadvantage? (see example below)
Can it be done in other ways? With interfaces?
This code shows what I try to do:
class A {
function horse() {
echo "horse";
}
}
class B {
function jump() {
// $A = new A; ... don't want to add this in each method.
$A->horse(); // Fails - $A is out of scope ($A = new A;).
// A::horse(); // Old code style - works.
// $this->horse(); // Works if you extend A - not self-documenting.
// $this->A->horse(); // Fails - out of scope.
}
}
$A = new A;
$B = new B; // Better to use "$B = new B($A);" ?
$B->jump(); // fails - the horse is sleeping.
Edit
Well, I am building a MVC-framework and I want to re-use code from other classes.
Some real-world examples:
a database object that is being passed across classes.
a "url" class that creates/manipulates URLs - used by other classes.
... and a code example:
class url {
function anchor($url,$name) {
return "{$name}";
}
}
class someclass {
function text($str,$url) {
return "{$str}. " . $url->anchor($url,"Read more...");
}
}
I think what you are asking for is multiple inheritance where you could extend both A and B like this
<?php
class C extends A,B {
//...
}
This however is not possible in PHP for good reasons(it actually is creating more problems than it's trying to solve).
Now you might ask yourself if there is any alternative to multiple inheritance and the answer is: Yes, there is! Have a look at the strategy pattern(as Benjamin Ortuzar also has pointed out).
UPDATE:
I just read your question a second time and figured that you might be looking for the singleton pattern, which lets you instantiate an instance of an class only once like this:
class A
{
protected static $_instance;
protected function __construct() //prohibit creating instances from outside
{ }
public static function getInstance()
{
if( self::$_instance === NULL ) {
self::$_instance = new self();
}
return self::$_instance;
}
}
$instance = A::getInstance();
Now A::getInstance() always returns the same instance of A which you can use in B and you can have both the advantages of dynamic functions and the accessibility of static functions.
UPDATE2:
Your database belongs into a registry if you can have more than one db-connection. If you're absolutely certain that you will always need only one db-connection you could as well make it a singleton.
For the URL helper I'd suggest writing a static class if you can and if you really need it to be dynamic make it a singleton, as mentioned before.
I think that this should work:
$B = new B();
$B->jump();
But you should read/refer to http://www.php.net/manual/en/language.oop5.php
Of course you should import the class if you're accessing it from a different php file. And if you're in the object you're calling the method of you should use
$this->jump();
I would suggest reading about the factory and strategy pattern. You can read more about this from chapter one of this fantastic book. link text
I would recomend you reading the whole book.
Maybe (just guessing) you're looking for something like aggregation in COM:
Aggregation is the object reuse mechanism in which the outer object exposes interfaces from the inner object as if they were implemented on the outer object itself.
You can build something like that with the "magic method" __call. Each time a method is called that isn't callable in the object's context this method is invoked and your code can decide what to do with this call. E.g. it can test if another object that is stored as a property of the "outer" object exposes a method with that name and than call that inner object's method.
class Foo {
protected $inner = null;
public function __construct($inner=null) {
if ( is_null($inner) && !is_object($inner) ) {
throw new Exception('...');
}
$this->inner = $inner;
}
public function __call($name, $arguments) {
// also check http://uk.php.net/is_callable
if ( !is_null($this->inner) && method_exists($this->inner, $name) ) {
return call_user_func_array( array($this->inner, $name), $arguments);
}
else {
// add some error handler here
throw new Exception('...');
}
}
function jump() {
$this->horse();
echo " jumps";
}
}
class Bar {
function horse() {
echo "horse";
}
}
$foo = new Foo(new Bar);
$foo->jump();
This works. But I'd recommend something like that only for quite specific circumstances. The most obvious reason beeing that it's hard to tell from the outside what this object $foo really can and cannot do.

Is what seems like polymorphism in PHP really polymorphism?

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.

Categories