Php extend method while overriding it - php

Is it possible to extend a parent class method while overriding it ? For example:
class Foo {
public function edit() {
$item = [1,2];
return compact($item);
}
}
class Bar extends Foo {
public function edit() {
// !!! Here, is there any way I could import $item from parent class Foo?
$item2 = [3,4]; //Here, I added (extended the method with) some more variables
return compact($item, $item2); // Here I override the return of the parent method.
}
}
The issue is that I cannot edit the Foo class in any way as it is a vendor package.
I don't want to edit the vendor methods I need to extend them (add something more to their return function)

If you used array_merge() instead it will probably show the results better...
class Foo {
public function edit() {
$item = [1,2];
return $item;
}
}
class Bar extends Foo {
public function edit() {
$item = parent::edit(); // Call parent method and store returned value
$item2 = [3,4]; //Here, I added (extended the method with) some more variables
return array_merge($item, $item2); // Here I override the return of the parent method.
}
}
$a = new Bar();
print_r($a->edit());
This will output -
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
So the call to parent::edit() will return the array from the parent class and this will be added to the array from the second class function.
Update:
I can't test this, but hopefully this will give you what your after...
class Foo {
protected function getData() {
return [1,2];
}
public function edit() {
return return view('view-file', compact($this->getData()));
}
}
class Bar extends Foo {
protected function getData() {
$item = parent::edit();
$item2 = [3,4];
return array_merge($item, $item2);
}
}
This means that the only time you create the view is in the base class, all you do is add the extra information in the derived class.

Related

How do I get all the function names in the class? (Without extends)

I am trying to get all the function names in a class with PHP. Using the get_class_methods() method. But it writes in the function names of the class I extend. what I want is just the function names of the class I'm calling.
Example :
class a {
public function index() {
//...
}
}
class b extends a {
public function indexb() {
//...
}
}
print_r(get_class_methods(new b()));
Output :
array([0] => index, [1] => indexb);
(index) I do not want this area.
Best Regards.
If you only want the methods for the child class, you're going to need to use Reflection.
<?php
class A
{
public function index() {}
}
class B extends A
{
public function indexB() {}
}
$reflection = new ReflectionClass('B');
$methods = array_reduce($reflection->getMethods(), function($methods, $method) {
if ($method->class == 'B') $methods[] = $method->name;
return $methods;
}, []);
print_r($methods);
And a working example: https://3v4l.org/veTeQ

PHP - pass variable between child and parent class

I would to know what is the best way to pass variable between parent and child class and updating this class all along the class is executed.
For example I have this parent class which execute is child class inside it:
class My_Class {
public $data;
public $data2;
public function __construct() {
}
public function output() {
$data['key1'] = 1;
$data['key2'] = 2;
$data2['key1'] = 'a';
$data2['key2'] = 'b';
$child_class = new Child_Class();
$child_class->output();
print_r($this->data); // only contains key1 & key2, I want to get key3 and 4 also
print_r($this->data2);
}
}
class Child_Class extends My_Class {
public function __construct() {
}
public function output() {
$data = parent::$data; // want to get data array but it's empty
$data2 = parent::$data2; // want to get data2 array but it's empty
this->set_data();
}
public function set_data() {
$this->data['key3'] = 3;
$this->data['key4'] = 4;
$this->data['key3'] = 'c';
$this->data['key4'] = 'd';
}
}
$class = new My_class();
$class->output();
Currently I execute the child class inside the parent class because I need to populate the main data of the parent class. This class will execute child class based on some variable.
What is the right way to inherit and assign variable from parent to child and child to parent. If I use dependency injection to retrieve the data in the extends class how can i assign the variable to the parent class?
"Do you have an example" - here you go....
<?php
class My_Class {
public $data = array('key1'=>1, 'key2'=>2);
public $data2 = array('key1'=>'a', 'key2'=>'b');
public function output() {
echo "MyClass::output\r\n";
print_r($this->data);
print_r($this->data2);
}
}
class Child_Class extends My_Class {
public function __construct() {
$this->data['key3'] = 3;
$this->data['key4'] = 4;
$this->data2['key3'] = 'c';
$this->data2['key4'] = 'd';
}
public function output() {
echo "Child_Class::output\r\n";
parent::output();
}
}
$class = new Child_Class();
$class->output();
prints
Child_Class::output
MyClass::output
Array
(
[key1] => 1
[key2] => 2
[key3] => 3
[key4] => 4
)
Array
(
[key1] => a
[key2] => b
[key3] => c
[key4] => d
)
see also:
https://en.wikipedia.org/wiki/Method_overriding
http://php.net/manual/en/keyword.parent.php
What is polymorphism, what is it for, and how is it used?
https://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29
https://en.wikipedia.org/wiki/Constructor_%28object-oriented_programming%29
My problem was a type, instead of $this->data I wrote $this->$data, the $ sign is only needed at the beginning of each statement.
My second problem was omitting the $this-> part when accessing variables on parent class thus creating locally scoped variables for parent class which was not shared with child classes, should have used $this->variable.

Unable to access a parent variables from child class

I want to reuse a few values from the parent class in the child class, but it seems that the child class cannot read the values that use the context $this in the parent method.
class Mother{
public function __construct($field,$val){
$this->field = $field;
$this->val = $val;
}
public function set(){
return array('val'=>$this->val,
'field'=>$this->field,
'test'=>"test");
}
}
class Sister extends Mother{
public function getVal(){
$val = parent::set();
print_r($val);
}
}
The output would be
Array ( [val] => [field] => [test] => test)
I have tried to turn the set() method static but that don't have anything to do with the problem. Can anyone tell me how to store the values in the parent class and pass it to the child class?
Your example will not print anything, because you don't call the class.
Try this
class Mother{
public function __construct($field,$val){
$this->field = $field;
$this->val = $val;
}
public function set(){
return array('val'=>$this->val,
'field'=>$this->field,
'test'=>"test");
}
}
class Sister extends Mother{
public function getVal(){
$val = parent::set();
return $val;
}
}
$class = new Sister('test1', 'test2');
print_r($class->getVal());

full inheritance behaviour with Decorator in php

I'm not really used to design pattern generally, and I never used Decorator. I want an object which can have different behaviour according to the context. These behaviours are defined in different classes. I guess Decorator does the trick. But I need that each decorator can access to the same properties, and call children methods first, like with inheritance. So here what I've done:
abstract class Component{
/**
* Used to access last chain Decorator
*
* #var Decorator
*/
protected $this;
protected $prop1;//These properies have to be accessed in any decorators
protected $prop2;
protected $prop3;
//this method is used to share properties with the childrens
public function getAttributesReferencesArray() {
$attributes=[];
foreach($this as $attr=>&$val)
$attributes[$attr]=&$val;
return $attributes;
}
}
class Foo extends Component{
public function __construct() {
$this->prop1="initialized";
//...
}
public function method1() {//this method can be "overrided" and called here
//...
}
public function method2() {//this method call the overrided or not method1
//...
$this->this->method1();
//...
}
}
abstract class Decorator extends Component{
/**
* Used to access parent component
*
* #var Component
*/
protected $parent;
public function __construct(Component $parent) {
$attributes=$parent->getAttributesReferencesArray();
foreach($attributes as $attr=>&$val)
$this->{$attr}=&$val;
$this->parent=$parent;
$this->this=$this;
}
public function __call($method, $args) {
if(!$this->parent instanceof Decorator &&
!method_exists($this->parent, $method))
throw new Exception("Undefined method $method attempt.");
return call_user_func_array(array($this->parent, $method), $args);
}
}
class Bar extends Decorator{
//this method call the component method (I guess Decorator classical way)
public function method1(){
//...
$this->parent->method1();
$this->prop2="set in Bar";
}
}
class Baz extends Decorator{
public function method2(){//this method call the overrided or not method1
//...
$this->this->method1();
//...
}
}
Now we can "construct" the "inheritance" according to the context:
//...
$obj=new Foo();
if($context->useBar())
$obj=new Bar($obj);
if($context->somethingElse())
$obj=new Baz($obj);
and run the object with abstraction of behaviour:
$obj->method1();
//...
It does what I want, but:
there isn't anymore encapsulation
$this->parent is ugly
$this->this is ugly
What do you think about that?
How can I access decorator ("children") method another way
How can I share properties like if they where protected in an inherited context
Is it a bad usage of Decorator?
Is there some more elegant pattern that does the trick
parent and this attributes are a kind of reinventing the wheel isn't it?
A real world example: the coffee machine
abstract class CoffeeFactory{// Component
/**
* Used to access last chain Decorator
*
* #var Decorator
*/
protected $this;
/**
* Used to access user choices
*
* #var CoffeeMachine
*/
protected $coffeeMachine;
protected $water;//the water quantity in cl
protected $coffeePowder;
protected $isSpoon=FALSE;
protected $cup=[];
//this method is used to share properties with the childrens
public function getAttributesReferencesArray() {
$attributes=[];
foreach($this as $attr=>&$val)
$attributes[$attr]=&$val;
return $attributes;
}
}
class SimpleCoffeeFactory extends CoffeeFactory{//Foo
public function __construct(CoffeeMachine $coffeeMachine) {
$this->coffeeMachine=$coffeeMachine;
$this->water=$coffeeMachine->isEspresso()?10:20;
$this->coffeePowder=$coffeeMachine->isDouble()?2:1;
$this->water-=$this->coffeePowder;
$this->this=$this;
}
private function addCoffeePowder(){
$this->cup["coffeePowder"]=$this->coffeePowder;
}
private function addSpoon(){
if($this->isSpoon)
$this->cup["spoon"]=1;
}
public function isWaterHot($boilingWater){
return $this->getWaterTemperature($boilingWater)>90;
}
private function addWater() {
$boilingWater=$this->getWaterForBoiling($this->water);
while(!$this->this->isWaterHot($boilingWater))
$this->boilWater($boilingWater);
$this->cup["water"]=$boilingWater;
}
public function prepare() {
$this->addCoffeePowder();
$this->addSpoon();
}
public function getCup() {
$this->this->prepare();
$this->addWater();
return $this->cup;
}
}
abstract class Decorator extends CoffeeFactory{
/**
* Used to access parent component
*
* #var Component
*/
protected $parent;
public function __construct(Component $parent) {
$attributes=$parent->getAttributesReferencesArray();
foreach($attributes as $attr=>&$val)
$this->{$attr}=&$val;
$this->parent=$parent;
$this->this=$this;
}
public function __call($method, $args) {
if(!$this->parent instanceof Decorator &&
!method_exists($this->parent, $method))
throw new Exception("Undefined method $method attempt.");
return call_user_func_array(array($this->parent, $method), $args);
}
}
class SugarCoffeeFactory extends Decorator{
protected $sugar;
public function __construct(Component $parent) {
parent::__construct($parent);
$this->sugar=$this->coffeeMachine->howMuchSugar();
$this->water-=$this->sugar;
$this->isSpoon=TRUE;
}
public function prepare() {
$this->cup['sugar']=$this->sugar;
$this->parent->prepare();
}
}
class MilkCoffeeFactory extends Decorator{
protected $milk;
public function __construct(Component $parent) {
parent::__construct($parent);
$this->milk=$this->coffeeMachine->howMuchMilk();
$this->water-=$this->milk;
}
public function prepare() {
$this->parent->prepare();
$this->cup['milk']=$this->milk;
}
public function isWaterHot($boilingWater){
//The milk is added cold, so the more milk we have, the hotter water have to be.
return $this->getWaterTemperature($boilingWater)>90+$this->milk;
}
}
//Now we can "construct" the "inheritance" according to the coffee machine:
//...
$coffeeFactory=new SimpleCoffeeFactory($coffeeMachine);
if($coffeeMachine->wantSugar())
$coffeeFactory=new SugarCoffeeFactory($coffeeFactory);
if($coffeeMachine->wantMilk())
$coffeeFactory=new MilkCoffeeFactory($coffeeFactory);
//and get our cup with abstraction of behaviour:
$cupOfCoffee=$coffeeFactory->getCup();
//...
The Decorator pattern is not made to do internal changes in the base class (you call this one parent). What you are doing is bad usage of this pattern. The Decorators should only change the output of the functions instead of playing with variables.
One solution is to define getters and setters for your protected variables and to call them from the Decorator.
Another solution is what I prefer personally and that is splitting the behaviour which is dependent on the context and the base class:
class Component {
protected $behaviour;
function __construct() {
$this->behaviour = new StandardBehaviour();
}
function method1() {
$this->prop2 = $this->behaviour->getProp2Value();
}
function setBehaviour(Behaviour $behaviour) {
$this->behaviour = $behaviour;
}
}
abstract class Behaviour {
abstract function getProp2Value();
}
class StandardBehaviour extends Behaviour {
function getProp2Value() {
return 'set by bahaviour ';
}
}
class BarBehaviour extends StandardBehaviour {
function getProp2Value() {
return parent::getProp2Value().' Bar';
}
}
class BazBehaviour extends BarBehaviour {
function getProp2Value() {
return 'set in Baz';
}
}
Now we can use it like this:
$obj=new Foo();
if($context->useBar())
$obj->setBehaviour(new BarBehaviour);
if($context->somethingElse())
$obj->setBehaviour(new BazBehaviour);
I hope this answers your question!
EDIT after comments
I see your point that the behaviours replace each other instead of chaining. This is indeed a typical problem for the decorator class. However you really shouldn't change the original class in a decorator class. A decorator class only 'decorates' output of the original. Below a typical example of how the decorator pattern would be used in the real world scenario you mentioned:
interface ICoffeeFactory {
public function produceCoffee();
}
class SimpleCoffeeFactory implements ICoffeeFactory{
protected $water;//the water quantity in cl
public function __construct() {
$this->water=20;
}
protected function addCoffeePowder($cup){
$cup["coffeePowder"]=1;
return $cup;
}
protected function addWater($cup) {
$cup["water"]=$this->water;
return $cup;
}
public function produceCoffee() {
$cup = array();
$cup = $this->addCoffeePowder($cup);
$cup = $this->addSpoon($cup);
$cup = $this->addWater($cup);
return $cup;
}
}
class EspressoCoffeeFactory extends SimpleCoffeeFactory {
public function __construct() {
$this->water=5;
}
protected function addCoffeePowder($cup){
$cup["coffeePowder"]=3;
return $cup;
}
}
abstract class Decorator implements ICoffeeFactory {
function __construct(ICoffeeFactory $machine)
}
class SugarCoffee extends Decorator{
public function produceCoffee() {
$cup = $this->factory->produceCoffee();
if ($cup['water'] > 0)
$cup['water'] -= 1;
$cup['spoon'] = TRUE;
$cup['sugar'] += 1;
return $cup;
}
}
class MilkCoffee extends Decorator{
protected function produceCoffee() {
$cup = $this->factory->produceCoffee();
$cup['milk'] = 5;
return $cup;
}
}
//Now we can "construct" the "inheritance" according to the coffee machine:
//...
$coffee=new SimpleCoffeeFactory();
if($coffeeMachine->wantSugar())
$coffee=new SugarCoffee($coffee);
if($coffeeMachine->wantMilk())
$coffee=new MilkCoffee($coffee);
//and get our cup with abstraction of behaviour:
$cupOfCoffee=$coffee->produceCoffee();
//...
Still a bit incomplete but it does basically everything:
abstract Component class that everything extends.
abstract Decorator class that modifies classes extending Component.
It's a lot of code so here's the pastebin link:
[Old] http://pastebin.com/mz4WKEzD
[New] http://pastebin.com/i7xpYuLe
Components
Can extend one another
Can modify / add / remove properties
Can share properties with decorators
Decorators
Can attatch functions to components
Can modify / add / remove component properties
Example Input
$Sugar = 1;
$DoubleSugar = 1;
$Cofee = new SimpleCofee();
$Tea = new SimpleTea();
$Cofee->Produce();
$Tea->Produce();
print "\n============\n\n";
if($Sugar)
{
new SugarCube($Cofee);
$Cofee->Produce();
new SugarCube($Cofee);
$Cofee->Produce();
}
if($DoubleSugar)
{
new SugarCube($Tea);
$Tea->Produce();
new SugarCube($Tea);
$Tea->Produce();
}
OutPut
Making coffee....
Adding Water: 150
Making cofee: array (
'cofeee' => 25,
)
Making tea....
Adding Water: 150
Making tea: array (
'tea' => 25,
)
============
Making coffee....
Adding sugar: 1
Adding Water: 140
Making cofee: array (
'cofeee' => 25,
'Spoon' => 1,
)
Making coffee....
Adding sugar: 1
Adding sugar: 1
Adding Water: 120
Making cofee: array (
'cofeee' => 25,
'Spoon' => 1,
)
Making tea....
Adding sugar: 2
Adding Water: 130
Making tea: array (
'tea' => 25,
'Spoon' => 1,
)
Making tea....
Adding sugar: 2
Adding sugar: 2
Adding Water: 90
Making tea: array (
'tea' => 25,
'Spoon' => 1,
)
UPDATE
That was crazy but now children can overload parent functions. On top of that you can now use array interface $this['var'] to access shared properties. Hashes will be added automatically and transparently.
The only downside is that parents have to allow functions to be overloaded.
NEW Output
Making Cofee....
Adding Water: 150
Making Cofee: array (
'cofeee' => 25,
)
Making Tea....
Adding Water: 150
Making Tea: array (
'tea' => 25,
)
============
Making Cofee....
Adding sugar: 1
Adding Water: 140
Making Cofee: array (
'cofeee' => 25,
'Spoon' => 1,
)
Making Cofee....
Adding sugar: 1
Adding sugar: 1
Adding Water: 120
Making Cofee: array (
'cofeee' => 25,
'Spoon' => 1,
)
I have take over Produce!
But I'm a nice guy so I'll call my parent
Making Tea....
Adding sugar: 2
Adding Water: 130
Making Tea: array (
'tea' => 25,
'Spoon' => 1,
)
I have take over Produce!
But I'm a nice guy so I'll call my parent
Making Tea....
Adding sugar: 2
Adding sugar: 2
Adding Water: 90
Making Tea: array (
'tea' => 25,
'Spoon' => 1,
)
============
DoubleSugarCube::SuperChain(array (
0 => 'test',
))
SugarCube::SuperChain(array (
0 => 'DoubleSugarCube',
))
SimpleTea::SuperChain(array (
0 => 'SugarCube',
))
SimpleCofee::SuperChain(array (
0 => 'SimpleTea',
))
UPDATE
This is my final draft. I can't keep changing my solution bit by bit. If there is something wrong state it all in a list.
Removed callparent and put all functionality of it into parent::function
Children have access to parents properties.
Children can overload parent functions.
Overloading will start at base class all the way up till abstract class Decorator class. Afterwards the properties / methods are obtained from parent passed to constructor.
You said you liked your method of property sharing. So I haven't bothered to answer that.
I hope you'll accept the answer now. If not then I look forward to yours. I hope when you sort everything out you will share it with the rest of us.
Cheers
there is a solution to fit the coffeemachine problem
abstract class Coffee {
protected $cup = array();
public function getCup() {
return $this->cup;
}
}
class SimpleCoffee extends Coffee {
public function __construct() {
$this->cup['coffeePowder'] = 1;
$this->cup['water'] = 20;
$this->cup['spoon'] = FALSE;
}
}
abstract class Decorator extends Coffee {
private $_handler = null;
public function __construct($handler) {
$this->_handler = $handler;
$this->cup = $handler->cup;
}
}
class SugarCoffee extends Decorator {
public function __construct($handler) {
parent::__construct($handler);
$this->cup['water'] -= 1;
$this->cup['sugar'] = 1;
$this->cup['spoon'] = TRUE;
}
}
class MilkCoffee extends Decorator{
public function __construct($handler) {
parent::__construct($handler);
$this->cup['water'] -= 5;
$this->cup['milk'] = 5;
}
}
$wantSugar = TRUE;
$wantMilk = TRUE;
$coffee = new SimpleCoffee();
if($wantSugar)
$coffee = new SugarCoffee($coffee);
if($wantMilk)
$coffee = new MilkCoffee($coffee);
$cupOfCoffee = $coffee->getCup();
var_dump($cupOfCoffee);
and there is another real world example, I hope it can help you:
abstract class MessageBoardHandler {
public function __construct(){}
abstract public function filter($msg);
}
class MessageBoard extends MessageBoardHandler {
public function filter($msg) {
return "added in messageBoard|".$msg;
}
}
class MessageBoardDecorator extends MessageBoardHandler {
private $_handler = null;
public function __construct($handler) {
parent::__construct();
$this->_handler = $handler;
}
public function filter($msg) {
return $this->_handler->filter($msg);
}
}
class HtmlFilter extends MessageBoardDecorator {
public function __construct($handler) {
parent::__construct($handler);
}
public function filter($msg) {
return "added in html filter|".parent::filter($msg);
}
}
class SensitiveFilter extends MessageBoardDecorator {
public function __construct($handler) {
parent::__construct($handler);
}
public function filter($msg) {
return "added in sensitive filter|".parent::filter($msg);
}
}
$html = TRUE;
$sencitive = TRUE;
$obj = new MessageBoard();
if($html) {
$obj = new SensitiveFilter($obj);
}
if($sencitive) {
$obj = new HtmlFilter($obj);
}
echo $obj->filter("message");

How to get all the methods of a subclass?

I'm programming an object instance to other objects.
Now I need to validate an object instantiated.
The code i'm using is correct, but the objects are children of another object, so further back methods of parents.
Code:
<?php
class MyParentClass
{
...
$objectName = "subClassExample";
$obj = new $objectName();
print_r( get_class_methods( $obj ) );
...
}
?>
Return :
Array ( [0] => __construct [1] => myMethod )
The SubClass:
<?php
class subClassExample extends parentClass
{
public function myMethod()
{
return null;
}
}
?>
I need to return:
Array ( [0] => myMethod )
The parent Class:
<?php
class parentClass
{
function __construct ()
{
return null;
}
}
?>
I hope I can help, I really appreciate it.
Greetings!
P.S.: Excuse my English is not my language, I speak Spanish and Norwegian Bokmal.
You can do this with PHP's Reflection­Docs:
class Foo
{
function foo() {}
}
class Bar extends Foo
{
function bar() {}
}
function get_class_methodsA($class)
{
$rc = new ReflectionClass($class);
$rm = $rc->getMethods(ReflectionMethod::IS_PUBLIC);
$functions = array();
foreach($rm as $f)
$f->class === $class && $functions[] = $f->name;
return $functions;
}
print_r(get_class_methodsA('Bar'));
Output:
Array
(
[0] => bar
)
You may do this check inside a child or a parent class if you need only UNIQUE child's methods:
$cm = get_class_methods($this); //Get all child methods
$pm = get_class_methods(get_parent_class($this)); //Get all parent methods
$ad = array_diff($cm, $pm); //Get the diff
Keep in mind: get_class_methods returns all types of methods (public, protected etc.)

Categories