Get called a subclass method from a superclass - php

I have a big problem. How to get called subclass method from a superclass. Please execute below code.
class Model {
public function render(){
echo '<br />class: '.get_class($this).' -- function: '.__FUNCTION__;
}
}
class Product extends Model {
public function show(){
$this->render();
}
}
class User extends Model {
public function index(){
$this->render();
}
}
$p = new Product();
$u = new User();
echo $p->show();
echo $u->index();
result :
class: Product -- function: render
class: User -- function: render
How to get subclass method name instead of render?
Thanks.

You can get that information using debug_backtrace().
I am curious as to why you want this - it could indicate a flaw with your design if you need this for anything other than debugging.

The __FUNCTION__ thingie is replaced at compile-time by the name of the function it is in. So no matter how your object model is structured, you'll get the function where __FUNCTION__ is met by PHP's preprocessor.
The best you can do here, if you want to know the name of the method being called, is to add it as a parameter to the method render() :
class Model {
public function render($methodName){
echo '<br />class: '.get_class($this).' -- function: '. $methodName;
}
}
And add the name in the method calls :
class Product extends Model {
public function show(){
$this->render(__FUNCTION__);
}
}
class User extends Model {
public function index(){
$this->render(__FUNCTION__);
}
}

Could you go into detail as to why you need this?
I'm not sure what you are trying to do, but especially when you are developing a PHP framework you should restrict yourself to the basic rules of inheritance.
Maybe you could illustrate a little better what you're trying to achieve with this.

Couldn't you simply change it to the following?
class Model {
protected $_type='unspecified';
public function render(){
echo '<br />class: '.$this->_type.' -- function: '.__FUNCTION__;
}
}
class Product extends Model {
public function __construct(){
$this->_type = 'product';
}
public function show(){
$this->render();
}
}
class User extends Model {
public function __construct(){
$this->_type = 'user';
}
public function index(){
$this->render();
}
}
Or is there any reason why that doesn't work for you?

You could move the logic which works out what you are rendering into the superclass, e.g.:
class Model {
public function render($type){
echo '<br />class: '.get_class($this).' -- function: '.$type;
}
public function show() {
$this->render('show');
}
public function index() {
$this->render('index');
}
}
class Product extends Model {
public function show(){
//some stuff
parent::show();
}
}
class User extends Model {
public function index(){
parent::index();
}
}

I don't really recommend this to you, but what you could do is throw an exception and catch it right away.
Then you can use the stack trace of this exception to find out which function called your render method.
I know that it works, but both performancewise and codingwise this is not a good option.
UPDATE:
<?php
class bla {
function test1() {
$this->test2();
}
function test2() {
$method = "";
try {
throw new Exception("bla");
} catch(Exception $e) {
$trace = $e->getTrace();
$method = $trace[1]['function']);
}
echo $method; //will echo test1
}
}
$blub = new bla();
$blub->test1();
Hope you get what I'm trying to illustrate.

Related

How can I injected a function before call a function?

I have a problem, I cannot call a function before all functions.
I have a parent class - that is a repository.
class Repository {
public function find(/*..*/){/*..*/}
public function findAll(/*..*/){/*..*/}
public function findBy(/*..*/){/*..*/}
public function findA(/*..*/){/*..*/}
public function findB(/*..*/){/*..*/}
/* then 100+ more public function */
}
And I want to create an "Adapter class" that will be calling a function that run before all only public functions BUT I don't want "overwriting" all functions of the parent.
I tried this solution:
class OwnRepo extends Repository{
public __call($methods, $args){/**/}
}
BUT the __call method not working with public methods
How can I solve this problem?
Thank you!
** UPDATE **
Sorry I was not clear!
My controller implements a model, I don't want to change/rewrite the functions of the controllers.
class IndexController {
public function index(){
$model = new Model(); // will return a OwnRepo object
$a = model->findAll();
}
}
In my opinion you can't do this with inheritance. You have to check if the desired method exists in the Repository class and then call it.
Try this one:
class Repository
{
public function find($a,$b,$c)
{
return "find $a $b $c";
}
}
class OwnRepo
{
function __call($name, $arguments)
{
if (method_exists('Repository', $name)) {
//some action before
$repo = new Repository();
$result = call_user_func_array(array($repo, $name), $arguments);
//some action afterwards
return $result;
} else {
die("Method " . $name . " does not exist");
}
}
}
$o = new OwnRepo();
echo $o->find(1,2,3);

How do I properly set method of derived class as callable for a parent class?

I am writing a basic class with some call_user_func() and then derived class with a method I want to be called from said call_user_func(). It looks as follows:
class Basic
{
private $InputHandler = null;
public function SetNewHandler(callable $NewHandler)
{
$this->InputHandler = $NewHandler;
}
public function ProcessInput()
{
call_user_func(array($this,$this->InputHandler));
}
}
class Specific extends Basic
{
public function Handler()
{
echo "Handler() is called\n";
}
}
$spec = new Specific();
$spec->SetNewHandler('Specific\Handler');
$spec->ProcessInput();
unset($spec);
Obviously it does not work since Specific\Handler is not recognized as a valid callable.
But what is the proper way to achieve this outcome? Parent class should be oblivious to the details of implementation of derived class and\or handler method.
I use php 7.4
I would just create a default handler method in the base class:
class Base
{
public function ProcessInput()
{
$this->Handler();
}
public function Handler()
{
// Some default code or just leave empty
echo "Base Handler() is called\n";
}
}
class Specific extends Base
{
public function Handler()
{
echo "Specific Handler() is called\n";
}
}
$spec = new Specific;
$spec->ProcessInput();
This way you don't need to manually bind the handler you want to use for each instance (which could be cumbersome). If you want a new handler, create a new class with that handler.
Here's a demo
If you made the call with call_user_func(array ($this, $this->InputHandler)); a method name is expected as the 2nd array element.
class Basic
{
private $InputHandler = null;
public function SetNewHandler($NewHandler)
{
$this->InputHandler = $NewHandler;
}
public function ProcessInput()
{
call_user_func(array($this,$this->InputHandler));
}
}
class Specific extends Basic
{
public function Handler()
{
echo "Handler() is called\n";
}
}
$spec = new Specific();
$spec->SetNewHandler('Handler');
$spec->ProcessInput();
Instead of call_user_func(Array($this, $this->InputHandler)); does this work here too:
$method = $this->InputHandler;
$this->$method();
or this:
$this->{$this->InputHandler}();
Alternatively: A callable is passed similarly as described by #Magnus Eriksson in the comment.
class Basic
{
private $InputHandler = null;
public function SetNewHandler(callable $NewHandler)
{
$this->InputHandler = $NewHandler;
}
public function ProcessInput()
{
call_user_func($this->InputHandler);
}
}
class Specific extends Basic
{
public function Handler()
{
echo "Handler() is called\n";
}
}
$spec = new Specific();
$spec->SetNewHandler([$spec,'Handler']);
$spec->ProcessInput();

Error calling a interface method in php

Hey guys i have this sample code and i want to call the method like this code:
<?php
interface Item{
function getRes();
}
class Weapon implements Item{
public function getRes(){
echo "Res";
}
}
abstract class Player implements Item{
public function defend(){
$this->Item->Weapon->getRes();
}
}
?>
I know this doesn't work but how is the best way to do this call.
If you are inheriting the Item class in player (which I don't think a player is a type of item ;) ), you would need to implement the getRes function.
Moving away from that, you will most likely want to rely on dependency injection (DI) in order for your player to get a weapon.
interface Item {
function getResponse();
}
interface AttackItem extends Item {
}
interface DefenseItem extends Item {
}
class Sword implements AttackItem {
public function getResponse(){
return "Swing of the sword!";
}
}
class Shield implements DefenseItem {
public function getResponse(){
return "Defend with the shield!";
}
}
class Player {
public function __construct(AttackItem $attackItem, DefenseItem $defenseItem) {
$this->attackItem = $attackItem;
$this->defenseItem = $defenseItem;
}
public function attack(){
return $this->attackItem->getResponse();
}
public function defend(){
return $this->defenseItem->getResponse();
}
}
$player = new Player(new Sword(), new Shield());
echo $player->attack() . "\n";
echo $player->defend() . "\n";

Why use a return when calling parent?

I am learning OO PHP and I was experimenting with using a parent::method in a child class. I noticed i had to use an "extra" return for the output of the parent method to show up. Could someone explain me why this is?
This is the code I used and in the code I made a comment.
class ShopProduct {
public $productnumber;
public function __construct($productnumber) {
$this->productnumber = $productnumber;
}
public function getSummary(){
return $this->productnumber;
}
}
class BookProduct extends ShopProduct {
public function __construct($productnumber) {
parent::__construct($productnumber);
}
public function getSummary() {
return parent::getSummary(); // if i dont use return it doesnt work? why is that?
// parent::getSummary(); is not enough it seems.
}
}
$product = new BookProduct(11111);
echo $product->getSummary();
?>
public function getSummary() {
return parent::getSummary(); // if i dont use return it doesnt work? why is that?
// parent::getSummary(); is not enough it seems.
}
Replace parent::getSummary() with any other function or method call:
public function getSummary() {
foo();
}
Of course you wouldn't expect getSummary to return anything in this case, right? Just because the method you're calling is parent::... doesn't change anything about this behaviour. It does not return automagically, because you may want to do something like this:
public function getSummary() {
$summary = parent::getSummary();
return "Book: $summary";
}
BTW, if the only thing your method does is call its parent, you can leave out the entire method. In other words, this:
class BookProduct extends ShopProduct {
public function __construct($productnumber) {
parent::__construct($productnumber);
}
public function getSummary() {
return parent::getSummary();
}
}
is exactly the same as this:
class BookProduct extends ShopProduct { }

Get name function in PHP

I have some classes:
class A
{
private $_method;
public function __construct()
{
$this->_method = new B();
}
public function demo()
{
$this->_method->getNameFnc();
}
}
class B
{
public function getNameFnc()
{
echo __METHOD__;
}
}
I'm trying to get the function name of a class B class, but I want the function getNameFnc to return 'demo'. How do I get the name 'demo' in function getNameFnc of class B?
Well, if you really want to do this without passing a parameter*, you may use debug_backtrace():
→ Ideone.com
public function getNameFnc()
{
$backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
echo $backtrace[1]['function'];
}
* this would be the recommended way although one should never need to know which function has been previously called. If your application relies on that fact, you have got a major design flaw.
You will need to use debug_backtrace to get that information.
I haven't tested the code below but I think this should give you the information you want:
$callers = debug_backtrace();
echo $callers[1]['function'];
Why not pass it?
class A
{
private $_method;
public function __construct()
{
$this->_method = new B();
}
public function demo()
{
$this->_method->getNameFnc(__METHOD__);
}
}
class B
{
public function getNameFnc($method)
{
echo $method;
}
}
Or use __FUNCTION__ if you don't want the class name.

Categories