I create parent class for my models, it look like this
class Model {
protected static $cache = [];
public static function load($id)
{
return static::$cache[$id];
}
public static function findById($id)
{
$model = static::find($id);
static::$cache[$id] = model;
return model;
}
...
}
And i have two child class, examples
class A extend Model {}
class B extend Model {}
then, i write
A::findById(1);
B::findById(1);
$a = A::load(1);
$b = B::load(1);
I think type of class $b is class B, but not, it is class A, because function "load" use static cache and load result from function A::findById(1). Why?
By accessing static class properties as static::$cache
you tell the interpreter to use the $cache
property of the class used to call the method and not the one of the class where the method is defined.
In plain English, when you call A::findById()
you expect that findById()
uses the property $cache
of A
and not the one of Model
. The same for A::load()
and similar for B::findById()
and B::load()
.
The question now is: do the A
and B
classes declare a static property $cache
on their own? Because if they do not declare this property, the static::
in front of $cache
in the function A::findById()
cannot find A::$cache
and uses Model::$cache
instead. The same for B::findById()
.
The easy solution to your problem is to declare the protected static $cache
property in all classes that extend Model
.
The correct solution is to not use static properties and methods. Static properties and methods are not OOP. They are procedural programming (and thinking) disguised as OOP code. Code that is difficult to understand and test.
static properties are inherited, if you want to have them separately, redefine them
class A extend Model { static $cache; }
class B extend Model { static $cache; }
also what you are trying to do is bad OOP practice.
this is how you can do it proper way
class CacheFactory
{
static public function createModelCache($model)
{
static $instances = [];
if (!isset($instances[$model])) {
$instances[$model] = new Cache($model);
}
return $instances[$model];
}
}
class Cache
{
protected $name;
protected $data = [];
public function __construct($name)
{
$this->name = $name;
}
public function get($key)
{
return isset($this->data[$key]) ? $this->data[$key] : null;
}
public function set($key, $value)
{
$this->data[$key] = $value;
}
}
abstract class Model
{
abstract protected $name;
/**
* @type Cache
*/
protected $cache;
public function __construct()
{
$this->cache = CacheFactory::createModelCache($this->name);
}
public function findById($id)
{
if (($data = $this->cache->get($id)) !== null) {
return $data;
}
$data = ...;
$this->cache->put($id, $data);
}
}
class A extends Model
{
protected $name = "modelA";
}
class B extends Model
{
protected $name = "modelB";
}
this just an example and you can change few bits like
CacheFactory::createModelCache
to Cache
get_class
instead using abstract protected $name
Cache
classbut thing is - you just don't use static
everywhere, this is not how you code in OOP
from my example you can see the only thing what is static
is an array with Cache
objects and factory method. this is only thing you need to store globally.