l00k
l00k

Reputation: 1545

PHP call parent class method

class Foo {
    protected static $a = 1;
    protected $b = 2;

    public function func() { return 'foo' . static::$a . $this->b; }
}
class Bar extends Foo {
    protected static $a = 3;
    protected $b = 4;

    public function func() { return 'bar' . static::$a . $this->b; }
}

$obj = new Bar();
$obj->func(); // returns of course 'bar34'

Is there any option in PHP to call func() from Foo class? In C++ I would cast $obj to Foo and simply call func()

Bar* obj = new Bar();
Foo* obj2 = (Bar*) obj;
obj2->func(); // returns 'foo14';

Upvotes: 1

Views: 709

Answers (4)

iainn
iainn

Reputation: 17417

If you want to get down and dirty with Reflection then it's possible, but I'd strongly argue that this shouldn't be used anywhere near any production code. If you've got an instance of a child class, then you've got it for a reason, and if it's overridden a parent method then that has also happened for a reason.

Assuming you already know all this, then with that disclaimer out of the way, this should work in any remotely recent version of PHP:

class Foo { public function func() { echo 'I am the parent'; } }
class Bar extends Foo { public function func() { echo 'I am the child'; } }

// Create instance of child class
$bar = new Bar;

// Create reflection class
$reflected = new ReflectionClass(get_class($bar));

// Get parent method
$method = $reflected->getParentClass()->getMethod('func');

// Invoke method on child object
$method->invokeArgs($bar, []);

// I am the parent

See https://3v4l.org/NP6j8

Upvotes: 2

Loek
Loek

Reputation: 4135

This isn't exactly what I'd call pretty, but it works and is relatively similar to what you described for C++; It works by calling get_parent_class() and then abusing PHP's ability to create objects from strings.

<?php

class Foo {
    public function func() { echo 'foo'; }
}
class Bar extends Foo {
    public function func() { echo 'bar'; }
}

$obj = new Bar();
$obj->func(); // Prints 'bar'

$parentClassString = get_parent_class($obj);
$newObj = new $parentClassString; // Gotta love PHP for magic like this
$newObj->func(); // Prints 'foo'

See this snippet to see it in action.

EDIT

It's a lot of work, but you could use so called Late Static Binding, perhaps more clearly explained in Jokerius's answer here. This requires you to write a crapload of custom code though, which I don't think is preferential. Overall the short answer seems to be: it isn't really possible.

Upvotes: 1

Leigh Bicknell
Leigh Bicknell

Reputation: 872

This to me looks like a design issue more than anything else. However if I were to handle this in a way that were easily readable and without rethinking my design I would do:

<?php
class Foo {
    public function func() { return 'foo'; }
}
class Bar extends Foo {
    public function func() { return 'bar'; }
    public function parentFunc() { return parent::func(); }
}

$obj = new Bar();
$obj->parentFunc(); // returns of course 'foo'

Loek's answer also works, but doesn't call the method on the objects parent. It just calls the method on the classes parent. It all depends on the functionality you are looking for.

You could also do something like:

<?php
class Foo {
    public function func() { return 'foo'; }
}
class Bar extends Foo {
    public function func($parent = false) { 
        if ($parent) {
            return parent::func();
        }
        return 'bar';
    }
}

$obj = new Bar();
$obj->func(true); // returns of course 'foo'

Which is similar but without the need for the extra method.

Personally though I feel this issue likely requires a rethink in code design more than a coding solution.

-- edit --

To elaborate on 'a rethink in code design', I would ask myself "Why do I need an object that has two methods with the same name, but different functionalities? Is this not a job for two different objects? Trace the issue backwards until you find the design issue. Or the point at which the decision needs to be made as to which object your framework requires.

Upvotes: 1

Davit Huroyan
Davit Huroyan

Reputation: 302

I don't know should it help you but try to add this function in Bar class

public function callParent($function){
    return parent::$function();
}

and call

echo $obj->callParent("func");

[UPDATED] Also you can write cast function yourself something like this

public function castAs($newClass) {
    $obj = new $newClass;
    foreach (get_object_vars($this) as $key => $name) {
        $obj->$key = $name;
    }
    return $obj;
}

Upvotes: 0

Related Questions