Jump to content

Static class members & inheritance -- troubles


blaster999

Recommended Posts

Hello,

 

I am experiencing problems with static class members. For example, I have these classes:

abstract class ActiveRecord {
    protected static $db_fields = array();
    protected $DB_TABLE_NAME // the name of the table

    public function loadTableDef()
    {
        // here I load the table's filed list into self::$db_fields
    }
}

class Test1 extends ActiveRecord {
    protected $DB_TABLE_NAME = 'users';
}

class Test2 extends ActiveRecord {
    protected $DB_TABLE_NAME = 'lang_list';
}

$t1 = new Test1();
$t2 = new Test2();

$t1->loadTableDef();
$t2->loadTableDef();

 

And here's a surprise: both Test1 and Test2 share the same $db_fields (althoug these are different classes), which is not what I want. Is there a way to work around this issue?

You miss my point. $t1 and $t2 are instances of different classes (both inherited from ActiveRecord). I want all instances of Test1 share the same value of $db_fields, but that it would be different from the value of $db_fields in all the instances of Test2.

You miss my point.

 

If you mean "you don't understand what I'm trying to accomplish", you're absolutely right.

 

$t1 and $t2 are instances of different classes (both inherited from ActiveRecord).

 

Duh.

 

I want all instances of Test1 share the same value of $db_fields,

 

They do because they point to the same reference,

 

but that it would be different from the value of $db_fields in all the instances of Test2.

 

That's where you stop making sense. The static property is just that: static. ActiveRecord::$db_fields will be the same ActiveRecord::$db_fields, no matter what you do. It is confined to the class scope. Visibility is not the same as scope.

I don't understand why Test1::$db_fields must be the same as Test2::$db_fields. And when I write "self::$db_fields", I mean it, not "parent::$db_fields".

 

Test1::$db_fields and Test2::$db_fields do not exist. Only ActiveRecord::$db_fields exists. Declaring something static confines it to the scope it was declared in.

"confines" is the wrong word for it though, sorry about that. What I mean to say is that once you declare a variable or property static, the same reference will be used within that scope. New references will not be created. I don't know how else to explain it. If you don't understand variable referencing, there's a whole new topic to study right there.

To add on -- remove the static keyword from before the variable, or define it separately in Test1 and Test2.  Obviously it's easier to remove the keyword.

 

What 448191 wanted to know is why you declared it static to begin with?  Was there a reason, or was completely at random?

What 448191 wanted to know is why you declared it static to begin with?  Was there a reason, or was completely at random?

 

Well, I was under impression that PHP will create new static variables for each subclass (like other languages do IIRC). I was about to implement the ActiveRecord pattern, so each inherited class would work with a separate DB table, so it would make sense for all instances of, say, Test1 would share the same value for db_fields (because they all would work with the 'users' table). Each instance holds data from exactly 1 row from the table they are meant to work with.

 

BTW, I understand why PHP acts this way. I don't understand why was it designed to work this way. It's kind of counter-logical.

I don't know how it works in other languages, but this same seems perfectly logical to me.  Static mean "does not change", so if a variable is static, why would it be different anywhere?  Creating new static variables for each subclass, to me, is illogical considering what static means.

 

Do other languages handle it differently?

Do other languages handle it differently?

 

In fact, yes. That's what makes static variables much more useful than they are in PHP5. BTW, I am not the only one who has the same problem: see http://socket7.net/article/php-5-static-and-inheritance for example.

 

Maybe there is a way to emulate my expected behavior without code-duplication?

BTW, I am not the only one who has the same problem: see http://socket7.net/article/php-5-static-and-inheritance for example.

 

That is not the same issue as you are describing. The man has three different static members, and only one method to retrieve them. The 'self' keyword in PHP is not dynamic, it doesn't change, i.e.: it is static.

 

What he (and you, I reckon) expect is a reference to the class at the bottom of the hierarchy (like the string returned by get_class()), what you get is a reference to the class the keyword was found in when parsing (like the string returned by __CLASS__). I'll agree with the guy that would be nice to have a build in mechanism to dynamically create a static reference to the latter. But there isn't.

 

BTW, I am not the only one who has the same

Maybe there is a way to emulate my expected behavior without code-duplication?

 

What you're trying to do is not possible. The very least you need is different declarations of $db_fields. You can write code that will dynamically reference to the different static members, but it's not pretty. The only effective way I've come across is using eval().

 

A better solution would be to simply use instance variables.

Ok, I see... Could you please give me a hint on how to get the desired effect using eval?

 

The solution I see now is to use $db_fields[get_class($this)] instead of $db_fields. It's an ugly hack, and is not safe (each ActiveRecord subclass would have full access to static variables of all other subclasses).

I've used something similar to the array solution you describe for lists of valid codes for 'code objects'. In such a case (when you have large amount of objects sharing the same reference) it might be worth the effort, but in general I don't really recommend it. Besides, the PHP engine internally doesn't make copies of variables until they actually change (Flyweigths, in a sense). So I'm not so sure it actually has any performance benefits. Just use non-static properties instead.

 

It does work though. You can prevent inappropriate access by checking the type in a getter.

 

abstract class Foo {
   
   private static $bars = array();

   protected function getBar(){
      return self::$bars[get_class($this)];
   }
   protected function setBar($value){
      self::$bars[get_class($this)] = $value;
   }
}

Thanks! I think your solution might be apropriate.  The main reason I wanted to use static members was not to boost performance of PHP code, but rather to limit the number of DB queries (if I need to create, say, 10 instances of Test1, the query to determine the table fields will only be run once).

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.