Configuration Registry
Page 1 of 2 12 LastLast
Results 1 to 15 of 18

Thread: Configuration Registry

  1. #1
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,764

    Configuration Registry

    Hi guys,
    In an effort to continue reducing my reliance on global variables I thought I would make a simple config registry. Here is the code for the class:
    PHP Code:
    <?php

    namespace core;

    class 
    config {
        use 
    traits\backtrace// vBulletin seems to be removing the namespace slashes
        
        
    public $settings = array();
        
        public function 
    __construct(Array $settings) {
            foreach( 
    $settings as $k => $v ) {
                if( 
    is_array($v) ) {
                    
    $this->settings[$k] = new config($v);
                } else {
                    
    $this->settings[$k] = $v;
                }
            }
        }
        
        public function 
    __get($name) {
            if( isset(
    $this->settings[$name]) ) return $this->settings[$name];
            
    trigger_error('Undefined property '.$name.$this->getCallerTrace(),E_USER_ERROR);
            return 
    NULL;
        }
        
        public function 
    __set($name,$val) {
            
    $this->settings[$name] = $val;
        }
        
        public function 
    __isset($name) {
            return ( isset(
    $this->$name) || isset($this->settings[$name]) );
        }
        
        public function 
    __unset($name) {
            if( isset(
    $this->settings[$name]) ) unset($this->settings[$name]);
        }
    }
    And of course his is an extremely simplified use case:
    PHP Code:
    $config = array();
    $config['database']['engine'] = 'mysql';
    $config['database']['user'] = 'username';
    $config['database']['pass'] = 'password';
    $config['database']['schema'] = 'database';
    $config['database']['host'] = 'localhost';
    $config['mail']['type'] = 'smtp';
    $config['mail']['host'] = 'localhost';
    $config['mail']['post'] = 587;
    $config['mail']['user'] = 'user@domain.net';
    $config['mail']['pass'] = 'mysupersecretemailpassword';

    $config = new \core\config($config); // For some reason vBulletin is removing slashes here that point to the namespace

    $PDO = new PDO($config->database->engine .':dbname='$config->database->schema .';host='$config->database->host$config->database->user$config->database->pass);

    $mail = new Mailer($config->mail->host$config->mail->port$config->mail->user$config->mail->pass$config->mail->type); 
    Basically I'm not even sure if this is the right way to do a config registry (or if it even qualifies as a registry) but I was hoping you guys would give me your feedback (or critique as it were) on this simple class.
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  2. #2
    High Energy Magic Dept. NogDog's Avatar
    Join Date
    Aug 2006
    Location
    Ankh-Morpork
    Posts
    13,885
    Might be a good candidate for the singleton pattern, just to ensure that you don't end up with multiple configuration objects floating around.

    You might consider putting the actual configuration settings in a non-PHP file that is read/processed by your configuration object. (A JSON file could be a quick and simple way to organize the data and is easy to read into a PHP array via json_decode().)
    Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett

    "But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because hes a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html


    eBookworm.us

  3. #3
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,764
    How would I use a singleton pattern and still have it be a child of itself? Or would this part have to change completely?
    PHP Code:
            foreach( $settings as $k => $v ) { 
                if( 
    is_array($v) ) { 
                    
    $this->settings[$k] = new config($v); 
                } else { 
                    
    $this->settings[$k] = $v
                } 
            } 
    My example wasn't a good one, because in reality my plan was to pass just the DB Config object to my database wrapper, etc. Like so:
    PHP Code:
    $db = new myDBWrapper($config->database);
    $mail = new myMailWrapper($config->mail); 
    Maybe I don't understand something with singleton, but I thought the idea behind it was once an object of that type was made, from that point forward it can't be made again only reused?

    As far as using a JSON file, I like this idea, but would it still be possible to keep settings in separate files? Right now I have a folder called config, with files in it called database.cfg.php mail.cfg.php global.cfg.php etc and I use glob to include them. So my configuration initialization looks like this right now:
    PHP Code:
    $config = array(); // to prevent undefined variable at first use
    $files glob(APPROOT 'config/*.cfg.php');
    foreach( 
    $files as $file ) {
       require_once(
    $file);
    }
    $config = new Config($config); 
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  4. #4
    Senior Member traq's Avatar
    Join Date
    Jun 2011
    Location
    so.Cal
    Posts
    949
    I use objects for config properties - it's easier to access dynamically than assoc. arrays are (plus I like typing -> much more than ['...']). If you made a "configProperty" class, then the config class itself could still be a singleton.

  5. #5
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,764
    Quote Originally Posted by traq View Post
    I use objects for config properties - it's easier to access dynamically than assoc. arrays are (plus I like typing -> much more than ['...']). If you made a "configProperty" class, then the config class itself could still be a singleton.
    I'm sorry I don't understand at all what you mean. Any chance you could show a link explaining what you mean? Or perhaps an example if a link isn't readily available.
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  6. #6
    High Energy Magic Dept. NogDog's Avatar
    Join Date
    Aug 2006
    Location
    Ankh-Morpork
    Posts
    13,885
    Quote Originally Posted by Derokorian View Post
    How would I use a singleton pattern and still have it be a child of itself? Or would this part have to change completely?
    I did not see (during my quick scan) that you were doing that. I guess you could create a ConfigContainer (or some better named class ) that might be a child of your config class, with the only change being to implement the Singleton pattern, but the cost/benefit analysis of doing that would depend on whether you have any concern or not about multiple instances existing (or if you would rather control that logically instead of structurally).

    The other option might be for each type of config to be a separate, child class that is a singleton -- perhaps extending an abstract config class? Again, whether it's worth the effort (and would require a new -- if small -- class definition for each new config type) is essentially an application size/scope/complexity question best answered by you.

    Personally, I'm lazy enough that I'd probably just have one config class with everything in an array (or array of objects), generated from a JSON file.
    Code:
    {
        "database": {
            "host": "localhost",
            "login": "foo",
            "password": "bar"
        },
        "mail": {
            "smtp_host": "mail.foo.bar",
            "user": "john",
            "password": "doe"
        }
    }
    Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett

    "But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because hes a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html


    eBookworm.us

  7. #7
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,764
    Hmm looking at the JSON formatted like that leads me to this thought: file_get_contents on the globbed files and concatenated together like this:
    PHP Code:
    // db.json
        
    "database": {
            
    "host""localhost",
            
    "login""foo",
            
    "password""bar"
        
    }

    // mail.json
        
    "mail": {
            
    "smtp_host""mail.foo.bar",
            
    "user""john",
            
    "password""doe"
        
    }

    // ConfigHandler.class.php
    class ConfigHandler {
       public 
    $config = array();
       private static 
    $_instance NULL;

       public static function 
    getInstance() {
          if( 
    is_null(self::$_instance) ) {
             
    self::$_instance = new ConfigHandler();
          }
          return 
    self::$_instance;
       }

       private function 
    __construct() {
          
    $files glob(APPROOT .'config/*.json');
          
    $cfg '{';
          foreach( 
    $files as $file ) {
             
    $cfg .= file_get_contents($file) .',';
          }
          
    $cfg rtrim($cfg,',') .'}';
          
    $cfg json_decode($cfg);
          foreach( 
    $cfg as $k => $v ) {
             if( 
    is_array($v) ) {
                
    $this->config[$k] = new Config($v);
             } else {
                
    $this->config[$k] = $v;
             }
          } 
    //foreach
       
    //construct
    }//class 
    Questions: Did I do singleton right? Do you think I should do sub-classes still? In which case I might have to dynamically call that class, something like:
    PHP Code:
    $class $k.'Config';
    $this->config[$k] = new $class($v); 
    I feel like having identical subclasses is a waste, I would end up just doing the following since they wouldn't have to behave differently:
    PHP Code:
    abstract class Config {
       public 
    $settings = array();

       public function 
    __construct() {
          
    // construct code
       
    }
       public function 
    __get($k) {
          return 
    $this->settings[$k];
       }
       public function 
    __set($k,$v) {
          
    $this->settings[$k] = $v;
       }
    }
    class 
    DatabaseConfig extends Config {}
    class 
    MailConfig extends Config {} 
    Maybe I just don't understand, but what is the point then of even creating the subclasses if they don't have different methods and/or properties.
    Last edited by Derokorian; 04-13-2012 at 12:33 PM.
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  8. #8
    High Energy Magic Dept. NogDog's Avatar
    Join Date
    Aug 2006
    Location
    Ankh-Morpork
    Posts
    13,885
    Quote Originally Posted by Derokorian View Post
    ....but what is the point then of even creating the subclasses if they don't have different methods and/or properties.
    Just me brain-storming -- I don't particularly care for it either.
    Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett

    "But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because hes a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html


    eBookworm.us

  9. #9
    Senior Member traq's Avatar
    Join Date
    Jun 2011
    Location
    so.Cal
    Posts
    949
    I'll explain a little (and I didn't actually use a singleton pattern, or make a specific subclass for the properties - I just used stdClass -- but you could do those things. making it a singleton might actually be helpful):
    PHP Code:
    class config{

    public function 
    __construct(){
         
    // load "default" config options here, however you want to do that
         // pass the options to the addConfig method
    }

    public function 
    addConfig$property ){
    // $property could be key=>value, JSON, etc.
        
    if( is_array$property ) ){  return $this->addConfig_array$property ); }
        if( 
    $array = @json_decode$property,TRUE ) ){ return $this->addConfig_array$array ); }
        return 
    FALSE;
    }

    public function 
    addConfig_array$property ){
        foreach( 
    $property as $k=>$v ){
            
    // if config property doesn't exist yet, set it
            
    if( !isset( $this->$k ) ){ 
                
    $this->$k $v
                return 
    TRUE;
            }
            
    // otherwise, to avoid accidental overwriting, ignore it
            //    (use changeConfig() method instead)
        
    }
        return 
    FALSE;
    }

    public function 
    changeConfig$property ){
        
    // however you want to approach that
    }

    }

    // usage:

    $config = new config();

    $DB = array(
        
    'host' => 'localhost'
       
    ,'user' => 'username'
       
    ,'pass' => 'password'
       
    ,'name' => 'database name'
    );

    $config->addConfig( array( $DB ) );
    // this would actually be done automatically in the constructor, of course

    print "My database password is {$config->DB->pass}"
    This isn't the actual code, just the idea behind what I did. I'll try to find it when I get home.

    The reason I went with objects vs. arrays is that I wanted some properties to be private, and I was using __get and __set to work with them, but I was running into trouble trying to work with my parameters in $array['index'] format -- whereas using $object->property worked just fine.

  10. #10
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,764
    Ok playing around with suggestions this is what I've come up with: Using a singleton ConfigHandler to hold Config objects. Each config object will be specific to something, such as mail, database, local file system, etc. I even took the singleton a step further and created an function to use the ConfigHandler to return a single Config object. As always I welcome all comments and criticism.

    PHP Code:
    <?php
    /** ConfigHandler.class.php **/
    if( !define('ROOT') ) die('No direct access allowed.');

    namespace 
    core;

    class 
    ConfigHandler {
        use 
    traits\backtrace,
             
    traits\singleton;
        
        public 
    $configs = array();
        
        private function 
    __construct() {
            
    $config = array();
            
    $files glob(APPROOT .'config/*.config.php');
            foreach( 
    $files as $file ) {
                require_once(
    $file);
            }
            foreach( 
    $config as $k => $v ) {
                
    $this->configs[$k] = new Config($v);
            }
        }
        
        public static function 
    getInstanceOf($k) {
            if( isset(
    self::$_instance->configs[$k]) ) {
                return 
    self::$_instance->configs[$k];
            }
            
    trigger_error('Property '.$k.' does not exists'.self::$_instance->getCallerTrace(),E_USER_ERROR);
        }
        
        public function 
    __get($k) {
            return isset(
    $this->configs[$k]) ? $this->configs[$k] : NULL;
        }
        
        public function 
    __set($k,$v) {
            if( 
    is_a($v,'\core\Config') ) {
                 
    $this->configs[$k] = $v;
            }
            
    trigger_error('ConfigHandler can only hold class Config as properties'.self::$_instance->getCallerTrace(),E_USER_ERROR);
        }
        
        public function 
    __isset($k) {
            return isset(
    $this->configs[$k]);
        }
    }
    ?>

    <?php
    /** Config.class.php **/
    if( !defined('ROOT') ) die('No direct access allowed.');

    namespace 
    core;

    class 
    Config {
        use 
    traits\backtrace;
        
        public 
    $settings = array();
        
        public function 
    __construct(Array $settings) {
            foreach( 
    $settings as $k => $v ) {
                if( 
    is_array($v) ) {
                    
    $this->settings[$k] = new config($v);
                } else {
                    
    $this->settings[$k] = $v;
                }
            }
        }
        
        public function 
    __get($name) {
            if( isset(
    $this->settings[$name]) ) return $this->settings[$name];
            
    trigger_error('Undefined property '.$name.$this->getCallerTrace(),E_USER_ERROR);
            return 
    NULL;
        }
        
        public function 
    __set($name,$val) {
            
    $this->settings[$name] = $val;
        }
        
        public function 
    __isset($name) {
            return ( isset(
    $this->$name) || isset($this->settings[$name]) );
        }
        
        public function 
    __unset($name) {
            if( isset(
    $this->settings[$name]) ) unset($this->settings[$name]);
        }
    }
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  11. #11
    Senior Member
    Join Date
    Aug 2002
    Location
    Norway
    Posts
    160
    Design patterns can be useful, but avoid them if you dont need them. Why use a singleton at all for a config object. Why not create it in the bootstrap and pass it as an argument where its needed?

    Hi guys,
    In an effort to continue reducing my reliance on global variables
    Then you drop singletons also because its a pattern to give global access. When you really need something to have global access why not just make a global one?
    have a nice OO day!

  12. #12
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,764
    Singleton as global argument has been around for probably as long as singletons. I happen to disagree that singleton's introduce globalization. Personally I believe it to be no more 'global' than the data in a database, or a flat file. In the end its not globally available, but rather you can ask for it any where. Just like you can ask for the contents of a file from anywhere. Of course this is my position on the argument, obviously yours is the opposite.

    Second why would I want to make a global object or variable, and pass it as an argument to everything that needs it? This creates a chained effect, if I want to use a class that needs this argument from inside another class that DOESN'T need this argument, I then I have to pass it to the class that doesn't need it, just so the class it uses for a function can have it. This in turn (in my mind, correct me if I'm wrong) tightly couples everything together far more than should be necessary to simply load configuration settings. In the end you end up passing arguments to things that don't need it so they can pass it as an argument to something else. Instead of just having that something else ask for what it needs, without involving whatever is using it.
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  13. #13
    Pedantic Curmudgeon Weedpacket's Avatar
    Join Date
    Aug 2002
    Location
    General Systems Vehicle "Thrilled To Be Here"
    Posts
    21,843
    Quote Originally Posted by gammaster
    Then you drop singletons also because its a pattern to give global access.
    No, it's a pattern to ensure instantiation of only a single instance of an object. Typically representing some unique resource such as the system's environment ("the world").
    THERE IS AS YET INSUFFICIENT DATA FOR A MEANINGFUL ANSWER
    FAQs! FAQs! FAQs! Most forums have them!
    Search - Debugging 101 - Collected Solutions - General Guidelines - Getting help at all

  14. #14
    PHP Witch laserlight's Avatar
    Join Date
    Apr 2003
    Location
    Singapore
    Posts
    13,529
    Quote Originally Posted by Weedpacket
    Quote Originally Posted by gammaster
    Then you drop singletons also because its a pattern to give global access.
    No, it's a pattern to ensure instantiation of only a single instance of an object.
    It is a pattern for both
    Use Bazaar for your version control system
    Read the PHP Spellbook
    Learn How To Ask Questions The Smart Way

  15. #15
    Pedantic Curmudgeon Weedpacket's Avatar
    Join Date
    Aug 2002
    Location
    General Systems Vehicle "Thrilled To Be Here"
    Posts
    21,843
    Quote Originally Posted by laserlight View Post
    It is a pattern for both
    THE WORLD IS ROUND!!!


    On a more prosaic note: I can come up with use cases for multiple configuration registries (e.g., swapping between environments). The current configuration would be unique, and a registry would be part of that.
    THERE IS AS YET INSUFFICIENT DATA FOR A MEANINGFUL ANSWER
    FAQs! FAQs! FAQs! Most forums have them!
    Search - Debugging 101 - Collected Solutions - General Guidelines - Getting help at all

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •