blaster999 Posted November 14, 2007 Share Posted November 14, 2007 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? Quote Link to comment Share on other sites More sharing options...
448191 Posted November 14, 2007 Share Posted November 14, 2007 Why is that a surprise? $db_fields is static, it exists in the class scope. Instantiation will not create new references. If you don't want that, then don't make it static. What are your after, why did you make it static? Quote Link to comment Share on other sites More sharing options...
blaster999 Posted November 14, 2007 Author Share Posted November 14, 2007 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. Quote Link to comment Share on other sites More sharing options...
448191 Posted November 14, 2007 Share Posted November 14, 2007 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. Quote Link to comment Share on other sites More sharing options...
blaster999 Posted November 14, 2007 Author Share Posted November 14, 2007 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". Quote Link to comment Share on other sites More sharing options...
448191 Posted November 14, 2007 Share Posted November 14, 2007 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. Quote Link to comment Share on other sites More sharing options...
448191 Posted November 14, 2007 Share Posted November 14, 2007 "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. Quote Link to comment Share on other sites More sharing options...
nloding Posted November 14, 2007 Share Posted November 14, 2007 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? Quote Link to comment Share on other sites More sharing options...
blaster999 Posted November 14, 2007 Author Share Posted November 14, 2007 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. Quote Link to comment Share on other sites More sharing options...
nloding Posted November 14, 2007 Share Posted November 14, 2007 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? Quote Link to comment Share on other sites More sharing options...
blaster999 Posted November 14, 2007 Author Share Posted November 14, 2007 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? Quote Link to comment Share on other sites More sharing options...
448191 Posted November 15, 2007 Share Posted November 15, 2007 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. Quote Link to comment Share on other sites More sharing options...
blaster999 Posted November 15, 2007 Author Share Posted November 15, 2007 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). Quote Link to comment Share on other sites More sharing options...
448191 Posted November 15, 2007 Share Posted November 15, 2007 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; } } Quote Link to comment Share on other sites More sharing options...
blaster999 Posted November 15, 2007 Author Share Posted November 15, 2007 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). Quote Link to comment Share on other sites More sharing options...
aschk Posted November 15, 2007 Share Posted November 15, 2007 Static variables work EXACTLY the same as they do in other languages. What you failed to understand is HOW they work, and what they're good for. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.