Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static / Non-Static Method Issue

Tags:

oop

php

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.

like image 844
majic bunnie Avatar asked Jun 26 '12 21:06

majic bunnie


1 Answers

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);
like image 116
DaveRandom Avatar answered Sep 29 '22 06:09

DaveRandom