PHP: change a method behavior - php

I have an object with some protected fields and a method that uses them. The method doesn't do exactly what I need it to do, but I cannot change the original code since I am writing an add-on.
Is it somehow possible to extend the class and override the method so that I could call it on predefined objects of the original class? I thought about monkey patching but apparently it is not implemented in php.

You can override a method by extending the parent class, initiating the new class instead of the parent class and naming your method exactly the same as the parent method, that was the child method will be called and not the parent
Example:
class Foo {
function sayFoo() {
echo "Foo";
}
}
class Bar extends Foo {
function sayFoo() {
echo "Bar";
}
}
$foo = new Foo();
$bar = new Bar();
$foo->sayFoo() //Outputs: Foo
$bar->sayFoo() //Outputs: Bar

I hope below stategy will be works. asume that class is Foo and method is bar(). for override bar() method you have to make customFoo class as mentioned below.
class CustomFoo extends Foo{
public function bar(){
parent::bar();
}
}
I dont know actually what you need because you dont have explained in detail. Still I have tried my best. :)

Try creating a child class that extends the base or parent class that the object currently derives from.
Create a new method with exactly the same name as the method in the Parent class and put your logic in there.
Now instantiate your object from your new class, you would have succeeded in overriding that particular method and still have access to the methods and properties of the base class.

Problem is, once you've loaded the class, you can't officially unload it, and you do need to load it in order to extend it. So it's pretty tied up. Your best bet is to either hack the original class (not ideal) or copy paste the original class definition into a new file:
class ParentClass {
//Copy paste code and modify as you need to.
}
Somewhere after the bootstrapping of your framework:
spl_autoload_register(function ($class) {
if ($class == "ParentClass") { //Namespace is also included in the class name so adjust accordingly
include 'path/to/modified/ParentClass.php';
}
},true,true);
This is done to ensure your own modified class will be loaded before the original one.
This is extremely hacky so first check if the framework you're using has native support for doing this.

Related

Can php call a static alias?

In php, is it possible for a method in a parent class to use an alias in a child class from within an instance of the child class?
Parent class:
class ParentClass
{
public function getNewFoo()
{
return new Foo();
}
}
Child class:
use My\Custom\Path\To\Foo;
class ChildClass extends ParentClass
{
}
Code:
$child = new ChildClass();
return $child->getNewFoo();
I would like this code to return a new instance of My\Custom\Path\To\Foo() rather than a new instance of Foo().
I realize I can store the desired path to Foo in a class property, or I can simply instantiate the desired Foo in the child class. However, both of these seem redundant considering the path is already stored in the use statement in the child class.
You're asking a lot of PHP here. It's supposed to know that your use statement is going to impact something in a completely different class, in a completely different file, just because?
If PHP did that by default it would cause a lot of very strange problems for people. Re-define the method, or as you point out, store that property in the class itself.
I think a lot of developers would expect, or at least prefer that PHP behave the way it does.
It sounds like what you need here is a factory function that can be redefined in the subclass to behave differently, or in other words, that getNewFoo() should be overridden in the subclass to use the alternate version.

Invoke parent constructor from child as though it were in the child's scope

Background
In a project with a PHP 5.6 runtime, I need to work around some third-party code. This code will not be changed by the vendor, nor will it be removed from the codebase.
Specifically, the third-party code (let's call its namespace Theirs) contains a class (\Theirs\BaseClass) whose constructor instantiates another class (\Theirs\Detector).
BaseClassTheirs.php:
<?php namespace Theirs;
class Detector {
public function __construct() {
print "Theirs\n";
}
}
class BaseClass {
public function __construct() {
$detector = new Detector();
}
}
I do not want BaseClass to instantiate \Theirs\Detector. Instead, I want BaseClass to instantiate a different Detector class, from a different namespace (Mine) that is outside of the third-party's control.
In all other respects, though, I want BaseClass to behave as it does in the third-party code, including if the vendor later adds additional functionality to \Theirs\BaseClass. (I'll call this property "non-fragility" and the lack of it "fragility".) As such, it seems sensible for me to create my own \Mine\BaseClass as a child of \Theirs\BaseClass, inheriting everything from it.
If I take the fragile, non-DRY approach of copy-pasting \Theirs\BaseClass's constructor into \Mine\BaseClass, then \Mine\Detector is instantiated, as I desired:
BaseClassMine.php:
<?php namespace Mine;
include "BaseClassTheirs.php";
class Detector {
public function __construct() {
print "Mine\n";
}
}
class BaseClass extends \Theirs\BaseClass {
public function __construct() {
$detector = new Detector();
}
}
\\ Prints "Mine"
$obj = new BaseClass();
However, if I change this into a DRY, non-fragile approach by removing the duplicated code so that \Mine\BaseClass invokes exactly the same constructor, but as inherited from its parent rather than being copy-pasted, then \Theirs\Detector gets invoked, which is not what I want:
BaseClassMine.php:
<?php namespace Mine;
include "BaseClassTheirs.php";
class Detector {
public function __construct() {
print "Mine\n";
}
}
use \Mine\Detector;
class BaseClass extends \Theirs\BaseClass {
}
\\ Prints "Theirs"
$obj = new BaseClass();
This happens regardless of whether the file contains a use \Mine\Detector; line, as above.
Question
How can I get the best of both approaches?
I.e. how can I invoke \Theirs\Baseclass's constructor from \Mine\Baseclass's constructor in order to have it invoke \Mine\Detector, as though \Theirs\Baseclass's constructor had simply been copy-pasted into \Mine\Baseclass's context, but without actually copy-pasting it and introducing the corresponding fragility?
For instance, is there a good way to use reflection or some other introspective technique to dynamically read the parent's constructor and to "paste" it at runtime into the child class?
Related but not identical questions
late static binding | without modifying parent class with static keyword
Is there any way to set a property before calling a constructor?

PHP class extends not giving feedback

What I would like to do is chain a few classes together using "extends". It kinda works, but not like I expected it to. So I must be doing something wrong.
From what I gathered, when you extend a class you inherit all of its properties. So with that in mind I like to make my config file available in all classes. To do this I want to extend all classes on an autoLoader class. This seems logical to me, but correct me if I'm wrong.
I have two classes
AutoLoader
Class AutoLoader {
public $oConf = null;
public function __construct($oConfig) {
$this->$oConf = $oConfig;
}
public function getConf() {
return $this->$oConf;
}
}
other class
Class foo extends AutoLoader {
public function bar() {
var_dump($this->getConf());
}
}
My question is, why is the var_dump NULL.
It is strange to me cause this always returns the conf:
$autoLoader = new AutoLoader($array);
var_dump($autoLoader->getConf());
What am I missing here.
You are extending and inheriting the class structure, not the object instance.
Just take this code as an example:
$foo = new Foo('foo');
$bar = new Foo;
Would you expect $bar to have access to the argument 'foo' passed into the first object somehow? No. Extension doesn't change that.
You should be using composition or dependency injection (e.g. pass an autoloader into the constructor of Foo). Don't make Foo an Autoloader, give it an Autoloader if it needs one. When you extend a class, that new class is also its parent class. That means it could be used in place of the parent class. Anywhere you'd use an Autoloader class, you could substitute Foo instead. Does that make sense? Is Foo an Autoloader? Does $foo instanceof Autoloader == true make any sense? No.
If inheriting class have an own constructor, you are probably not passing the oConfig to the parenting class (Autoloader) in the case.
also, your constructor expects an config.
So you should be doing this in your child constructor if you don't have one:
function __construct($oConfig) {
parent::__construct($oConfig);
// rest of your constructor code here
}
You should create instance of foo class and give into constructor your config variable:
$config = 'My_config';
$foo = new foo($config);
$foo->bar();
Will output:
(string) "My_config"

Can you explain how Zend's Action controller operating?

Sorry for constantly re-editing my question but looks like this is the only way to ask it properly.
My original problem is the following pseudo-code (a controller and it's parent) isn't working as i would like to:
class Parent {
var $data = array();
public function __construct( OtherClass $otherClass ) {
$this->data = $otherClass->getData(); //contains some => thing
$this->init($otherClass->getClassName());
}
public function init( $className ) {
new $className; //new Child
}
public function __get( $name ) {
return array_key_exists($name, $this->data) ? $this->data[$name] : null;
}
}
class Child extends Parent {
public function __construct() {
echo $this->some; //won't return 'thing';
}
}
fireeyedboy helped me a lot (thank you) and pointed out Zend_Controller_Action is doing what i want but i can't understand how they do it?
Original question
I know there was some similar questions here but i cannot dump them. Also i know i can reverse the whole process so i can initialize Child first then call parent::__construct but this seems unwanted for me. How can i access Parent variables easily in my case?
Update:
Let me clarify a little bit. Child is an arbitrary controller. Parent is the mother of all controllers. Many frameworks are doing the same but controllers can utilize their parent controllers variables, methods or objects without calling parent::__construct (and therefore filling child class constructors with unnecessary arguments). I don't like to rewrite any of these frameworks but i'd like to understand how they're operating.
Your child class doesn't call parent constructor. Here's a fix:
class Child extends Parent {
public function __construct() {
parent::__construct();
echo $this->some;
}
}
Update: Parent classes' constructors aren't called automatically in PHP. See the documentation:
Note: Parent constructors are not
called implicitly if the child class
defines a constructor. In order to run
a parent constructor, a call to
parent::__construct() within the child
constructor is required.
So what you're asking does not happen. Either you have misinterpreted the class structure or how they operate. Note that PHP also supports legacy constructor naming (at least until 5.3.3): If there is no __construct() method in a class, PHP assumes the constructor is named after the class (ie. class Foo { function Foo() {}) treats the Foo() method as constructor).
Injecting ANYTHING using controller's construct is generally a BAD PRACTICE! Problem lies in your design. What kind of object is OtherClass? Is it DB adapter? Is it ACL? Is it some helper class?
If you need external class in your controller I suggest using action helpers. That's what they are created for ;) Or create an action helper that will fetch this OtherClass from somewhere when needed.
You should NEVER use __construct() to do any of your dirty work. That's what init() is used for. But it has no params. And there is a reason for that - again - you should not inject dependencies like this ;)
Update:
Note your class uses discouraged PHP4 member variable definition syntax. Try replacing your var with protected.
The problem is that your Child class does not call the base constructor.
Incidentally, Parent is not a valid class name in PHP. I have changed the class names for clarity. See below:
class ChildClass extends ParentClass {
public function __construct() {
parent::__construct(/* what goes here? */);
echo $this->some;
}
}
However, note the what goes here? part: your base class requires a reference to an OtherClass instance to be constructed. Therefore, since ChildClass IS-A ParentClass, it also needs to get such an instance somehow. You will need to either add a parameter to ChildClass::__construct and forward the value to parent::__construct, or somehow figure out a default value yourself.

Understanding Classes in PHP

I'm officially mentally retarded. [Let me explain]
I've never really given classes and their relationship any thought until today. I'm trying to figure out something that seems to be pretty obvious but since I'm stupid I can't see it.
Let's say I have a Core Class that will be extended from different files. How can children classes call functions from other siblings (that is if those are considered childs at all).
Sample Code: (don't kill me)
class cOne {
public function functionOne(){
echo "something";
}
}
Then on another file, I say:
class cOneChildOne extends cOne {
public function functionOne(){
echo "something from child one";
}
}
And yet on another file I say:
class cOneChildTwo extends cOne {
public function functionOne(){
echo "something from child two";
}
}
How would I have to create a new object, and when, so that I'm able to access functions from both childs and the parent class in a fashion similar to $newObject->Children->function(); I'm seriously considering the option that I've completely lost my brain today and can't think straight.
I've obviously doing something wrong since: $newObject = new cOne; creates the object but then the code from one of the subclasses is unable to access anything that's not directly in the core class or in itself.
Thanks
You can collect child instances in masters class static array
class C1{
static public $childs=array();
function __construct(){
self::$childs[]=$this;
}
}
class C1C1 extends C1{
function hi(){
echo 'hi from C1C1 <br />';
}
}
class C1C2 extends C1{
function hi(){
echo 'hi from C1C2 <br />';
}
}
$c1 = new C1C2();
$c2 = new C1C2();
$c3 = new C1C1();
$c4 = new C1C1();
$c5 = new C1C1();
$c6 = new C1C1();
foreach(C1::$childs as $c){
$c->hi();
}
The parent class cOne has no knowledge of the classes that extend it in php, so while you can call to the parent from a child class using parent::someFunction(), you cannot call the child classes from the parent. You also could not call functions from other classes that extend cOne from a class that extends cOne, also because cOne has no knowledge of classes that extend it.
You do have a fundamental misunderstanding.
Your two subclasses are different classes with a common ancestor. Each child essentially has knowledge of the parent, but the parent has no knowledge of the children, and the children have no knowledge of each other.
If you want child1 to be able to call methods of child2, then there is something wrong with your design. One solution would be to move the method from child2 to the parent class, so that child1 would also inherit that method.
you can use parent::functionOne(); to call functions of parent class from child class.
you can't call child classes' functions from parent class.
Help me or shoot me!!
Bang!!! =o)=o)=o)
When you create instance of class it only knows its methods and methods from its parents.
There is no way you can tell that there are other class who are extending same parent.
As kgb says, you can't create one object that will give you "access" to both sibling class' behaviour. If you instantiate a cOneChildOne, you'll get something that outputs "something from child one" (*). You could, if you use parent::functionOne(), copy cOne's behaviour, maybe to return "something\nsomething from child one" or whatever.
(*) Don't do this. Rather, return a string:
public function functionOne(){
return "something from child one";
}
This lets you compose your functions, output them to files, etc.
You could always just call cOneChildTwo from inside cOneChildOne statically if this suffices your requirement. $this in a method always points to the callee object (that's how parent::__construct() works), so you could use the callee's state inside cOneChildTwo for extended behaviour.
However, this would possibly imply that you'd require wrapper methods for every sibling's method. This is nothing Reflection can't solve though.
i think you're looking at object inheritance, classes and their relationships the wrong way.. what you've said is not really how inheritance in object oriented programming works. when you want to call a method/function of some other object, may it be an instance of the same class or not, what you need is a reference to that object that you are going to call. the keyword here is pass a reference. the one wanting to call must have a reference to the object it wants to communicate to.
child1.communicateWithAnotherChild(someOtherChild)
Why can't you have a static Array $children in the cOne class, and the __construct() methods for the classes that extend it just call cOne::addChild($this)? They could each implement a getChildren function which sends the request on to the superclass - Shouldn't that work?

Categories