php overriding method called by constructor in child class - php

I was playing around with a couple of classes to understand the relationship between parent and child. I setup the parent to have a constructor that calls an init method. Then when I add an init method to the child, it should override the parent init, shouldn't it? But what is happening is that both methods are being called.
To test this, I wrote a class named Model and a child called Instance. Here is the code:
$try = new Instance;
echo $try;
class Model{
public function __construct(){
$this->init();
}
public function init()
{
return $this->className();
}
public function __toString()
{
return $this->className();
}
public static function className()
{
return get_called_class();
}
}
class Instance extends Model
{
public function init()
{
echo "tada! ";
}
}
Gives the following output:
tada! Instance.
In class Model, I use the magic method __toString() to return the class name as a string. The constructor of the parent calls the parent init() method, which in this case echoes the class name.
My understanding is that if I write a child class, in this case the class is called Instance, with an init() method, it would overwrite the parent init() method, but that is not what is happening. In this case, it returns both init mehtods and I have no idea why. Can anyone explain this?

The fact is -
When you instantiate an object of Class "Instance" using "$try = new Instance;". it calls the constructor and since child class overrides "init" method, it prints "tada!".
On the other line you echo the object of Class "Instance" using "echo $try;" and a magic method __toString() implemented in parent class. So it print "Instance" as class name.
You can run only $try = new Instance; that will print only "tada!".

You are running two different commands. First you are instantiating the class with $try = new Instance; which is calling __construct. The __construct() in the parent class is calling init() which is using the child init() and returning tada!. Create a blank constructor in the child class to override the parent constructor.
The second command is when you echo the class: echo $try; using __toString() which is echoing Instance as defined in the parent class.
You can also add to a parent constructor by using:
public function __construct() {
...code...
parent::__construct();
...code...
}

Reason :
Since you don't have any constructor defined for your child class, the parent class constructor will be fired and that is why you get that output.
Explanation :
When you do
$try = new Instance;
The parent class constructor gets fired and it will call the init() which in turn calls the className() that does the get_called_class() , so eventually your init() in the child class will be called and you get the output "tada!" first.
And when you do..
echo $try;
The __toString() is called and returns you the class name Instance
So basically , If you had a constructor on your child class , you will not be getting the output "tada!"

In this case, it returns both init mehtods
No it doesn't;
'tada!' is being echoed by Instance::init() and 'Instance' is being echoed by Model::__toString().

Related

Determine the name of the calling class (parent or child) in parent class method

Looking for a clean way to determine the class (in this case, either parent or child class) of the method that calls a method in the parent class.
I thought late static binding could handle this, but seems like that only really works for calling a static method directly, and not from within an instantiated object's method.
Consider the following:
abstract class ParentClass {
public function parentMethod() {
self::_log("parent.non.static");
}
public static function parentStatic() {
self::_log("parent.static");
}
public static function getClassName() {
return __CLASS__;
}
protected static function _log($key) {
$prefix = 'graphite.key.prefix';
$class = static::getClassName(); // gets the object's class, not calling class
$g_key = "{$prefix}.{$class}.{$key}";
echo "{$g_key} \n";
// Graphite::increment($g_key);
}
}
class ChildClass extends ParentClass {
public function childMethod() {
self::_log("child.non.static");
}
public static function childStatic() {
self::_log("child.static");
}
public static function getClassName() {
return __CLASS__;
}
}
$obj = new ChildClass;
$obj->childMethod(); // graphite.key.prefix.ChildClass.child.non.static
$obj->parentMethod(); // graphite.key.prefix.ChildClass.parent.non.static
ParentClass::parentStatic(); // graphite.key.prefix.ParentClass.parent.static
ChildClass::childStatic(); // graphite.key.prefix.ChildClass.child.static
Looking for a clean way to get the class that calls the _log() method without having to pass it in as a parameter. Doesn't have to be static at all, but I was playing around with the late static binding, because I thought that would work, but it just gets the name of the instantiated object, not the child/parent class of the method that calls the _log() method :-/
Edit:
Just to be clear, I'm after getting the class name of the method that called _log() from within the instantiated object (like parentMethod() and childMethod()) Don't care if _log() is static or not. If that makes it easier, fine. But the static ParentClass::parentStatic() and ChildClass::childStatic() were just to show late static bindings and what I figured might work, but not from calling within an instantiated object
http://php.net/manual/en/function.get-called-class.php
class One {
public static function test() {
echo get_called_class() . PHP_EOL;
}
}
class Two extends One {}
One::test();
Two::test();
Output:
One
Two
Also, according to the top comment in the docs static::class also works as of PHP 5.5.
get_class will get the class name of a class instance. This can also be called on $this within a class. If you have a class that extends/implements another, $this will refer the the instantiated class, meaning the child class.
Another option is to use debug_backtrace to get the stack of functions that lead up to where you currently are. You can parse the returned array to get whatever you need including line numbers, classes, functions, methods, whatever.

Overloading function construct when extends class PHP

i have two class:
class BaseClass
{
public function __construct()
{
$this->init();
}
private function init()
{
//dosomething
}
}
class Myclass extends BaseClass
{
public function __construct()
{
}
}
now when i create:
$myclass = new Myclass;
function init is not running, somebody can help me?
That is because you are overriding your constructor within your child class. Just leave it out when you are not processing any tasks that differ from your parents constructor or call your parents constructor like that
class Myclass extends BaseClass
{
public function __construct()
{
parent::__construct(); // Call the parents constructor
// Do some stuff that explicitly belongs to the child class
}
}
Let's take a look on what the PHP docs say on it:
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. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method (if it was not declared as private).
Further reading:
PHP Docs - Constructors and Destructors

How do I access a parent's methods inside a child's constructor in PHP?

Say I have class child() and class parent(). The parent has a constructor and a few other public methods, and the child is empty apart from a constructor.
How do I go about calling a parent's methods inside of the child's constructor, as in:
Class Parent {
public function __construct() {
// Do stuff (set up a db connection, for example)
}
public function run($someArgument) {
// Manipulation
return $modifiedArgument;
}
}
Class Child extends Parent {
public function __construct() {
// Access parent methods here?
}
}
Say I want to call parents run() method, do I have to call a new instance of the parent inside the child constructor? Like so...
$var = new Parent();
$var->run($someArgument);
If so, what is the point of extends from a class definition POV? I can call a new instance of another class with the new keyword whether it extends the 'child' or not.
My (likely) wrong understanding was that by using extends you can link classes and methods from a parent can be inherited into the child. Is that only outside the class definition? Does using extend offer no efficiencies inside the class definition?
Because referring to the parent's run() method with the this keyword certainly doesn't work...
Use parent as predefined reference: parent::run(). This will ensure you call parent method. The same way you could call first parent constructor first or after child one - parent::__construct().
Class Child extends Parent {
public function __construct() {
parent::__construct();
// Access parent methods here?
$some_arg = NULL; // init from constructor argument or somewhere else
parent::run($some_arg); // explicitly call parent method
// $this->run($some_arg); // implicitly will call parent if no child override
}
}
If you dont have an implementation in child you could call $this->run($args), where it will again call parent run method.
To extend Rolice's answer
function a() {
echo 'I exist everywhere';
}
class A {
protected $a
function a() {
$this->a = 'I have been called';
}
function out() {
echo $this->a;
a();
}
}
class B extends A {
function __construct() {
parent::a();// original method
$this->a(); // overridden method
a();
}
function a() {
$this->a = $this->a ? 'I have been overwritten' : 'first call';
}
}
Study these to understand the difference

php calling parent function makes parent unable to load own vars

I have a Handler class that looks like this:
class Handler{
public $group;
public function __construct(){
$this->group = $this->database->mysql_fetch_data("blabla query");
//if i print_r($this->group) here it gives proper result
new ChildClass();
}
public function userGroup(){
print_r($this->group); //this is empty
return $this->group;
}
}
class ChildClass extends Handler{
public function __construct(){
$this->userGroup();
//i tried this too
parent::userGroup();
//userGroup from parent always returns empty
}
}
Workflow:
Handler is called from my index.php and the __construct is called
Handler needs to create $group
Handler creates child class
Child class calls Handler function
When I try to return $group in the function It tries to get $this->group from Child instead of Handler
Whenever I try to ask the parent something I can only access the parent function then inside the function the parent class can't find any of it's own variables
EDIT:
I figured using 'extends' would be useful in calling parent functions but it seems just passing $this on to the child will be easier.
You never called the parent constructor, so the group object is never initialized. You will want to do something like this.
class Handler{
public $group;
public function __construct(){
$this->group = $this->database->mysql_fetch_data("blabla query");
//if i print_r($this->group) here it gives proper result
new ChildClass();
}
public function userGroup(){
print_r($this->group); //this is empty
return $this->group;
}
}
class ChildClass extends Handler{
public function __construct(){
parent::__construct();
$this->userGroup();
}
}
If you had not overwritten the __construct method in your extended class, then the parent __construct would have automatically been called, but since you overwrote it in the extended class, you must tell it to call the parent's __construct in your extended class' __construct.

Calling method X from each parent

what i'm trying to do is call each method "init" from current class's parents.
I'm doing that to avoid programmers to have to call init method (parent::init()) each time they create an init method in a new controller.
Example:
class Aspic\Controller { } // main controller
class ControllerA extends Aspic\Controller { public function init() {/* do something 1 */}
class ControllerB extends ControllerA {}
class ControllerC extends ControllerB { public function init() { /* do something 2 */ }
class ControllerD extends ControllerC {}
As you can see the init methods do not call parent init method but i want my app (there is an option) do it.
Thus when I'm loading ControllerD, before calling it's init method (there isn't in the example but the app test it), i want to call each parent init method.
sound like this:
parent::init(); // Controller C init
parent::parent::parent::init(); // Controller A init
So i did :
if($this->_autoCallParentsInit) {
// Aspic\Controller is the main controller, which is the mother of all others
$aspicControllerRc = new \ReflectionClass('Aspic\\Controller');
$rc = new \ReflectionClass($this); // We are in D
$currPrefix = '';
// Calling each init methods of current class parent
// Avoid using parent::init() in each controller
while(($parentClass = $rc->getParentClass()) AND $aspicControllerRc->isInstance($parentClass)) {
/*
$aspicControllerRc->isInstance($parentClass)
=> because Aspic\Controller extends a "Base class". Thus, we stopped at Aspic\Controller
*/
$currPrefix .= 'parent::';
// Must have explicit method (not inherited from parent) BUT actually hasMethod does not care
if($parentClass->hasMethod('init')) {
call_user_func($currPrefix.'init');
}
}
}
This is not working because ReflectionClass::isInstance does not accept others argument than the object we want to test (and the not a ReflectionClass object representing it as in the example)
**
Simply:
I have an object $x, and i want to call the init method of each parent of the class of $x.
**
Is it possible ?
I hope i was clear :)
Thanks
ControllerB has an init() method by virtue of extending ControllerA, so you shouldn't have to call parent::parent::init() to get to A's from C. You should be fine to call parent::init() from ControllerD, which will call ControllerC's init() method. If ControllerC calls parent::init() it will be calling ControllerA's init() method.
If you're trying to skip the Controller's specific init() code when being called by a subclass, you could add a flag function init($call_parent = false) and then, from lower controllers, call parent::init(true);
If you're not using the classes statically (which, from your code not stating static function, I assume you're not), have you tried using the __construct() method? It gets automatically called when you instantiate the class, for example:
class MyClass {
public function __construct() {
echo 'Hello!';
}
}
$class = new MyClass();
That will automatically output 'Hello!', however if you extend the class and that child class contains a __construct() method you will have to put parent::__construct() inside the childs construct method, however you wont have to do it for every parent, just the once, for example:
class MyClassB extends MyClass {
public function __construct() {
parent::__construct();
echo 'World!';
}
}
class MyOtherClass extends MyClassB
public function __construct() {
parent::__construct();
echo 'How\'s it going!';
}
}
$class = new MyOtherClass();
That will output "Hello! World! How's it going!"

Categories