Page 1 of 3

New Idea! Class Variable Scope all to Private + one Get Set

Posted: Mon Sep 14, 2009 3:19 pm
by ctrLogicDotNet
Ok here's the thing, I'm just sharing an idea here to know what you people think of it?

Suppose I have a class:

Code: Select all

 
class firstClass{
    public static $variable = 'whatever';
    public static function get_variable(){
        return self::$variable;
    }
}
 
If I want to retrieve the static variable fro the public scope I can do the following:

Code: Select all

 
echo firstClass::$variable;
echo firstClass::get_variable();
 
which outputs:

Code: Select all

 
whatever
whatever
 
but if the class static variable was declared private like this:

Code: Select all

 
private static $variable = 'whatever';
 
so that I can restrict its manipulation from either a class extending this one or from the public scope.

But maybe I would like to be able to get the value of this static variable, or set it, or maybe be able to still do both...

Then only the second situation (with a public static declared method) would allow me to do so...

Suppose I have a 100 or more variables on which I would like to be able to do so... that means I would have to declare get and set methods for each of them (200 methods or so!!!).

I surely don't want to program 200 methods!

So I was trying to find a way to only have one get method and one set method in each of my classes...

This is what I've come up with
an interface containing some constants:

Code: Select all

 
interface constants_int{
    /**@CONST                               */
    // var flags
    const NO_AUTH                           = 0;
    const PUB_FLAG                          = 1;
    const PROT_FLAG                         = 2;
    const PRIV_FLAG                         = 3;
    // class variable prefixes
    const INI_PREF                          = '_I';
    const DEF_PREF                          = '_D';
    const FLAG_PREF                         = '_F';
    const STAT_PREF                         = '_';
}
 
and a class:

Code: Select all

 
class secondClass implements constants_int{
    private static $_D_variable = 'whatever';
    private static $_F_variable = array('GET'=>self::PUB_FLAG,'SET'=>self::PRIV_FLAG);
    private static $_variable = null;
    /*********************************************
    * Method that initialise the static variables 
    * still not set to their default values and
    * performs some additionnal prerequired tasks
    * and verifications for this class use
    */
    public static function ini(){
        $classVars = get_class_vars(__CLASS__);
        foreach($classVars as $varName=>$varValue){
            if($varValue===null){
                if  
                (   preg_match('/\A_[^DFI]/U',$varName) && 
                    array_key_exists(self::DEF_PREF.$varName,$classVars)
                )
                {
                    self::$$varName = self::${self::DEF_PREF.$varName};
                }
            }
        }
    }
    /*********************************************
    * Method to get different get flagged static and object
    * variables from either an array (which returns an
    * associative array) or from a string (which returns
    * the direct value).
    */
    private static function _get($getFlag,$mixed){
        $return;
        if(is_array($mixed)){
            $return = array();
            foreach($mixed as $toGet){
                $return[$toGet] = self::get($getFlag,$toGet);
            }
        }
        elseif(is_string($mixed)){
            if
            (   array_key_exists(self::STAT_PREF.$mixed,get_class_vars(__CLASS__)) &&
                isset(self::${self::FLAG_PREF.self::STAT_PREF.$mixed}) &&
                self::${self::FLAG_PREF.self::STAT_PREF.$mixed}['GET']<=$getFlag
            )
            {
                $return = self::${self::STAT_PREF.$mixed};
            }
            else{
                trigger_error('',E_USER_WARNING);
            }
        }
        else{
            trigger_error('',E_USER_WARNING);
        }
        return $return;
    }
    /*********************************************
    * Method which gets public flagged variables
    * from a public dependancy context or higher
    */
    public static function get1($mixed){
        return self::_get(self::PUB_FLAG,$mixed);
    }
    /*********************************************
    * Method which gets protected flagged variables
    * from a protected dependancy context or higher
    */
    protected static function get2($mixed){
        return self::_get(self::PROT_FLAG,$mixed);
    }
    /*********************************************
    * Method which gets private flagged variables
    * from a private dependancy context or higher
    */
    private static function get3($mixed){
        return self::_get(self::PRIV_FLAG,$mixed);
    }
    /*********************************************
    * Method to set different set flagged static and object
    * variables from either an associative array 
    * or from two arguuments (variable name followed by
    * its value).
    */
    private static function _set($setFlag,$mixed,$value=null){
        if(is_array($mixed)){
            foreach($mixed as $toSet=>$value){
                self::_set($setFlag,$toSet,$value);
            }
        }
        elseif(is_string($mixed)){
            if  
            (   array_key_exists(self::STAT_PREF.$mixed,get_class_vars(__CLASS__)) &&
                isset(self::${self::FLAG_PREF.self::STAT_PREF.$mixed}) &&
                self::${self::FLAG_PREF.self::STAT_PREF.$mixed}['SET']<=$setFlag
            )
            {
                self::${self::STAT_PREF.$mixed} = $value;
            }
            else{
                trigger_error('',E_USER_WARNING);
            }
        }
        else{
            trigger_error('',E_USER_WARNING);
        }
    }
    /*********************************************
    * Method which sets public flagged variables
    * from a public dependancy context or higher
    */
    public static function set1($mixed,$value=null){
        return self::_set(self::PUB_FLAG,$mixed,$value);
    }
    /*********************************************
    * Method which sets protected flagged variables
    * from a protected dependancy context or higher
    */
    protected static function set2($mixed,$value=null){
        return self::_set(self::PROT_FLAG,$mixed,$value);
    }
    /*********************************************
    * Method which sets private flagged variables
    * from a private dependancy context or higher
    */
    private static function set3($mixed,$value=null){
        return self::_set(self::PRIV_FLAG,$mixed,$value);
    }
}
secondClass::ini();
 
called this way:

Code: Select all

 
echo secondClass::get('variable');
 
outputs:

Code: Select all

 
whatever
 
but this would throw me an error:

Code: Select all

 
echo secondClass::set('variable','foo');
 
Note: I use prefixes in front of the variables name to distinguish:
  • '_D': default value initialise when calling secondClass::ini()
  • '_F': array containing the Get and Set flags
  • '_': static variables
With Late static binding I could even make extended class inheriting theses methods and use thos in all child classes... but I'm not developing under PHP 5.3.0 yet... maybe soon

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Mon Sep 14, 2009 3:27 pm
by ctrLogicDotNet
I haven't found any other way of doing something similar, anyone knows?
Maybe if I could determine if a variable within its class is declared private, protected or public...?

Would be nice to be able to declare these variable properties under one class variable definition statement when prefixed with a keyword maybe like this:

Code: Select all

 
private static $variable = properties(null,'whatever',self::PUB_FLAG,self::PRIV_FLAG);
 
properties(value,defaultValue,getFlag,setFlag)

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Mon Sep 14, 2009 4:01 pm
by jackpf
Hmm...forgive me if I've misunderstood...but can't you achieve the same effect with this:

I used the __get() function to format the variable $var whenever it's accessed.

Code: Select all

<?php
class foo
{
    private
        $var = 'this is private';
    
    public function __get($varname)
    {
        echo $this->format($this->$varname);
    }
    private function format($var)
    {
        return strtoupper($var);
    }
}
 
$foo = new foo;
echo $foo->var;
?>

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Mon Sep 14, 2009 6:36 pm
by ctrLogicDotNet
The thing is, I want to be able to control which variable can be accessed either to be read or to be modified under different scope (public, protected, private)...

from the class itself: all variables can be read and modified (flagged: public, protected, private)
from a child class: only those available from a protected scope (flagged: public, protected)
from public scope: only those made available under the public scope (flagged: public)

Code: Select all

 
public function __get($varname)...
 
is publicaly always available

would be nice to be able to have 3 __get functions:

Code: Select all

 
public function __get($varname)...
protected function __get($varname)...
private function __get($varname)...
 
is it possible, I don't think so....

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Mon Sep 14, 2009 11:54 pm
by ctrLogicDotNet
I've made some test, and my get method seems to be faster than the direct:

Code: Select all

 
class::$variable
 
way of retrieving a public static class variable...?!?
and also faster than:

Code: Select all

 
class::get_variable();
 
test made on a thousand variables inside one class, getting all of them in a loop from a public scope
  • My way: 0.00086593627929688 sec. - class file 3 to 4 times the Direct size
  • Direct: 0.0017569065093994 sec.
  • get_variable(): 0.0032391548156738 sec.
tested on Win XP, Intel P4 3.00GHz, PHP 5.2.9, Appache 2.2.11, 2048MB RAM

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Mon Sep 14, 2009 11:56 pm
by PHPHorizons
Hello,

To jackpf, the php manual has this to say about overloading:
PHP Manual wrote:Property overloading only works in object context. These magic methods will not be triggered in static context. Therefore these methods can not be declared static.
Of course you haven't defined your __get and __set methods statically, but since the topic of this post is about getting/setting static properties, I am assuming you meant to use a static __get/__set call. $this would not be available in that context.

Here's my take on it, if you want all three visibilities, and you want to be able to dynamically set/get static properties, then make three arrays. Give each array one of the visibilities. Then make three sets of get/set methods that get/set these three arrays. Apply the visibility to those get/set methods that match the array properties.

And bam, you've got the ability to get and set properties that are static and either public/protected/private.

Here's some sample code:

Code: Select all

<?php
 
class foo {
    
    static public $dataPublic               = array();
    static protected $dataProtected         = array();
    static private $dataPrivate             = array();
    
    static public function getPublic($key) {
        if (isset(self::$dataPublic[$key])) {
            return self::$dataPublic[$key];
        }
        return null;
    }
    static protected function getProtected($key) {
        if (isset(self::$dataProtected[$key])) {
            return self::$dataProtected[$key];
        }
        return null;
    }
    static private function getPrivate($key) {
        if (isset(self::$dataPrivate[$key])) {
            return self::$dataPrivate[$key];
        }
        return null;
    }
    static public function setPublic($key, $value) {
        self::$dataPublic[$key] = $value;
        return self;
    }
    static protected function setProtected($key, $value) {
        self::$dataProtected[$key] = $value;
        return self;
    }
    static private function setPrivate($key, $value) {
        self::$dataPrivate[$key] = $value;
        return self;
    }
    
}
 
foo::setPublic('blah', 'hehehe');
echo foo::getPublic('blah');

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Tue Sep 15, 2009 3:12 am
by Christopher
ctrLogicDotNet wrote:The thing is, I want to be able to control which variable can be accessed either to be read or to be modified under different scope (public, protected, private)...

from the class itself: all variables can be read and modified (flagged: public, protected, private)
from a child class: only those available from a protected scope (flagged: public, protected)
from public scope: only those made available under the public scope (flagged: public)
I am a little baffled by this thread? PHP does control access to properties based on their declaration as public, protected, private. I get the sense from your questions (and that you are doing timings) that you have made a wrong turn in how you are thinking about PHP and are trying to do something quite unnatural.

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Tue Sep 15, 2009 3:20 am
by onion2k
__get() is great, but every time I use it I find myself with something like...

Code: Select all

public function __get($var) {
 
  switch ($var) {
 
    case "weirdcase1": return "something other than the value"; break;
    case "weirdcase2": return "something other than the value"; break;
    case "weirdcase3": return "something other than the value"; break;
    default: return $this->$var;
 
  }
 
}
It's entirely my fault, I tend to build objects that do too much work rather than breaking them down into smaller objects, but it's annoying nonetheless so I avoid the magic functions if I can.

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Tue Sep 15, 2009 5:29 am
by jackpf
PHPHorizons wrote:Of course you haven't defined your __get and __set methods statically, but since the topic of this post is about getting/setting static properties, I am assuming you meant to use a static __get/__set call. $this would not be available in that context.
Oh yeah. Hmm...that's weird.

They've added a __callStatic() method in V 5.3....maybe they'll add a __getStatic() method or something in 6?

Yeah, my method only works with objects. But still...best way imo ;) It uses far less code.

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Tue Sep 15, 2009 7:39 am
by ctrLogicDotNet
to PHPHorizons:
This seams somehow to what I did...
Instead of adding a Get Set property to each static variable, you stack them into an array representing your Get/Set scope...
But in your exemple, scope on get and set are the same...
Sometimes, you want the user to retrieve the data but not set it...

to arborint:
arborint wrote: I am a little baffled by this thread? PHP does control access to properties based on their declaration as public, protected, private...
Like I've said
I haven't found any other way of doing something similar, anyone knows?
I'm not a php expert, but I'm not new to it either. If you know something I don't, I would be pleased to hear it :wink:

Sure I know the natural way of doing this, it would be to declare methods to get and set each properties with the proper (public, protected, private). I wanted to know if there could be an other way around, with only one get and set method.

But thanks everyone for your comments, suggestions and perspectives ont this thread

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Tue Sep 15, 2009 7:49 am
by Eran
I'm a little baffled by this thread as well - what are you trying to achieve, exactly? code doesn't exist in a vacuum, it is meant to solve problems. Describe the actual problem you are trying to solve and then we could comment on the approach...

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Tue Sep 15, 2009 9:38 am
by jackpf
I think what he is trying to achieve is to be able to access and format private properties of the class without having to have a separate function for each individual property :D

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Tue Sep 15, 2009 10:12 am
by ctrLogicDotNet
Exactly! :wink:
I've used PHPHorizons approach (filling static arrays with properties I want to get/set under different scope) instead of mine (additionnal properties prefixed)... (more esthetic)

Ok now I'll describe what I'm trying to achieve...

I want to build an interface on my dedicated server which contains code/classes/interfaces I want to reuse for different websites... I have an authentication class containing properties to identify which accounts(websites) can access these.
I systematically make all class_properties and object_vars private (to make sure I don't give access to public scope on some by inadvertence) and usually create methods to get or set each class_property/object_var I need to get/set.
The thing is I'm trying to figure out a different way than to define additional methods to do so.
Having one get and one set method I could implement in child classes (Late Static Binding coming soon for me)

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Thu Sep 17, 2009 1:33 am
by Christopher
ctrLogicDotNet wrote:The thing is I'm trying to figure out a different way than to define additional methods to do so.
I don't think it is specifically what you are doing that is baffling to me -- it is why you are doing it. You have this obvious Code Smell of too many accessor methods. Your solution seems to be to make the cow manure smell like chicken manure. Instead you should probably take a step back and investigate Tell Don't Ask.

Re: New Idea! Class Variable Scope all to Private + one Get Set

Posted: Thu Sep 17, 2009 5:38 am
by Eran
Your solution seems to be to make the cow manure smell like chicken manure
I love your analogies :P.

And this is what I was talking about jack, not the technical details. What problem is the OP trying to solve in this roundabout way