Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jrdi's avatar
Level 2

Static methods in extended classes

Hi,

sorry for my english, I'm not an english speaker. I'll do my best :)

I have a problem when I'm working with an extended model class. I would be delighted if you could help me.

Let's say that I have this model:

class ModelA extends Model
{
   ...
   public static function getFirstModel()
   {
       return self::first();
   }
}

Now, I create an extended model of ModelA:

class ModelB extend ModelA
{
   //
}

Then, I have this function (it isn't a method of the classes) which expect ModelB argument:

function randomFunction(ModelB $modelB = null)
{
  //
}

Ok, here is when I have a type problem, or even a OOP design problem. When i call this function with this: randomFunction(ModelB::getFirstModel()) throws an error saying that argument 1 must be instance of ModelB or null, instance of ModelA given. I guess it is because, at the end, a static method from ModelA is called.

I would like to have this behaviour:

ModelA::getFirstModel() // returns ModelA instance
ModelB::getFirstModel() // return ModelB instance

I could copy the static function into the ModelB class but as the function would be the same one, I would like to avoid duplicate code.

How can I deal with this situation?

Thanks!

0 likes
2 replies
Sergiu17's avatar

Hi, if I understood you correctly!

<?php

class FirstModel {
    public static function getClass()
    {
        return static::first();
    }

    public static function first()
    {
        return 'First Model';
    }
}

class SecondModel extends FirstModel {
    public static function first()
    {
        return 'Second Model';
    }
}

var_dump(FirstModel::getClass()); // First Model
var_dump(SecondModel::getClass()); // Second Model

Instead of self, use static

The idea with randomFunction

<?php

abstract class Model {
    abstract public function getClass();
}

class FirstModel extends Model {
    public function getClass()
    {
        return static::first();
    }

    public function first()
    {
        return 'First Model';
    }
}

class SecondModel extends FirstModel {
    public function first()
    {
        return 'Second Model';
    }
}

class ExplainHowItWorks {

    /**
     * @var Model $parent
     */
    private $parent;

    public function __construct(Model $parent) // Here, make sure you inject the parent class
    {

        $this->parent = $parent;
    }

    public function getRandom(){
        return $this->parent->getClass();
    }
}

var_dump((new ExplainHowItWorks(new FirstModel()))->getRandom()); // First Model
var_dump((new ExplainHowItWorks(new SecondModel()))->getRandom()); // Second Model
1 like
jrdi's avatar
Level 2

Hi @Sergiu17 , thanks for your help!

Ok, I've realized that the problem is in the cache. In my last post, I tried to simplify the code and that's why I didn't mention the cache. Sorry :( .

I'll be more specific. I have this

class ModelA extends Model
{
   public static function getFirst()
   {
        if (session()->has('first'))
        {
           return session()->get('first');
        }

        $first = self::first(); // or $first = static::first() or $first=ModelA::first()
    session()->flash('first', $first); // Then I store $first on flash cache
        
       return $first; 
  }
}

class ModelB extends ModelA
{
   //
}

If I call ModelA::getFirst(), a ModelA instance is returned and the flash data persisted is a ModelA instance. But after that, if I call to ModelB::getFirst(), as first is persisted in cache, it returns a ModelAinstance class instead of ModelB.

So, the error is thrown when I'm doing this:

    ModelA::getFirst();

       randomFunction(ModelB::getFirst()); //it expects a ModelB instance

When I'm calling to randomFuction(ModelB::getFirst()), key first exists in cache and I'm getting a ModelA instance. Then an error argument 1 must be instance of ModelB or null, instance of ModelA given is thrown.

I got a possible solution. I realized that if I define the function randomFunction(ModelA $model) instead of randomFunction(ModelB $model) it works regardless $model type (no matter if it's ModelA or ModelB)

Summing up, being ModelB extended from ModelA:

function randomFunction(ModelA $model){}

$modelA = new ModelA();
$modelB = new ModelB();

randomFunction($modelA); // Works
randomFunction($modelB); // Works too.

(...)

function randomFunction(ModelB $model) {}

$modelA = new ModelA();
$modelB = new ModelB();

randomFunction($modelA); // ERROR
randomFunction($modelB); // Works too.

So, I'm defining randomFunction(ModelA) as a way to accept ModelA and ModelB arguments as a "solution" or "walkarround" but I don't know if it is a good practice.

Thanks for your time and help!

Please or to participate in this conversation.