I am working on a simple ORM solution and have run into a tricky situation. Ideally, I'd like to be able to use methods in both a static context, and object context depending on how it is called. I am not sure if this is possible, but here is what I mean:
Say a User model wants to call where() statically, this currently works fine, for example:
$user = User::where('id = ?', 3);
Now, I also support relationships, for example a user can have messages. When this relationship is established I simply store a blank copy of a message model in the user model and set a foreign key. For example:
$user -> messages = new Message();
$user -> messages -> foreign_key = 'user_id';
Now, ideally, I would like to be able to call:
$user -> messages -> where('unread = ?', 1);
In a non-static context and make use of $this -> foreign_key when in this context so as to only pull messages where the foreign key matches the user's id. Is this type of context-switching possible in PHP? Any reference to $this from static context throws an error as its a static method and should not rely on $this (for obvious reasons, when being called from a static context, $this won't exist)
Are there any clever ways around this? I tried overloading the method to have two different prototypes, both with and without the static keyword but this threw a re-declaration error.
After quite a bit of playing around, I have found a way to make this workable without the Strict Standards
error mentioned by @drew010. I don't like it, it feels horrible, but it does work so I shall post this anyway.
Basically the idea is to make the method you want to be accessible private
and static
. You then define the __call()
and __callStatic()
magic methods, so that they will call the private static method. Now you may think "this doesn't solve the problem, I'm still stuck in a static context" - which you are but for a minor addition, you can append $this
to the arguments passed to the actual method in __call()
and fetch this as the last argument to the method. So instead of referencing $this
in an object context, you reference the third argument to get a reference to your own instance.
I'm probably not explaining this very well, just have a look at this code:
<?php
class test_class {
private $instanceProperty = 'value';
private static function where ($arg1, $arg2, $obj = NULL) {
if (isset($obj)) {
echo "I'm in an object context ($arg1, $arg2): I can access the instance variable: $obj->instanceProperty<br>\n";
} else {
echo "I'm in a static context ($arg1, $arg2)<br>\n";
}
}
public function __call ($method, $args) {
$method = "self::$method";
if (is_callable($method)) {
$args[] = $this;
return call_user_func_array($method, $args);
}
}
public static function __callStatic ($method, $args) {
$method = "self::$method";
if (is_callable($method)) {
return call_user_func_array($method, $args);
}
}
}
test_class::where('unread = ?', 1);
$obj = new test_class();
$obj->where('unread = ?', 2);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With