• PHP Help PHP Coding
  • Is it possible to assign Class constants in constructors with the latest PHP 5.5?

Just curious. It seems that this syntax is invalid for previous PHP:

class Foo{
    const Bar;

public function constructor($bar){
    self::Bar = $bar;   
}
}

For this reason PHP class constants aint really useful at all, unlike global constants in which you can actually assign its value by a string or number variable determined at runtime. Hows it with PHP 5.5.0 alpha? Is it possible to dynamically assign Class constants now?

    IMHO, this:

    Lord Yggdrasill;11019185 wrote:

    dynamically assign

    suggests that you shouldn't be using a "constant" but instead a private property that can only be accessed outside of the class, not assigned.

      That would be a significant change in how class constants work, since as currently implemented the value will always be the same for all instances of that class, and as such the assignment only happens when the class definition is first processed. If you were now to allow each instance to have a different value, you'd be dealing with a different animal. If anyone really felt PHP needed such a thing, then I would rather it were named something else to differentiate it from "normal" class constants. What might be nice is a "readonly" type of class variable, so that you would not have to mess around with private variables that can be accessed via get() to read but not via set() to write, e.g.:

      class Foo
      {
        // new hypothetical class property type:
        readonly $bar;
      
        public function __construct($bar)
        {
          $this->bar = $bar;
        }
      }
      
      $foo = new Foo('bar');
      echo $foo->bar; // works
      $foo->bar = 'fubar'; // exception
      
        NogDog;11019259 wrote:
          // new hypothetical class property type:
          readonly $bar;
        

        How about using "const" as a reserved word for this? And perhaps add a variable initialization list to the constructor as well.

          bradgrafelman;11019187 wrote:

          IMHO, this:suggests that you shouldn't be using a "constant" but instead a private property that can only be accessed outside of the class, not assigned.

          I've had a "readonly" __get() method for some time; I turned it into a trait when I started running PHP 5.4:

          /** 
           * allows "read-only" access to [specified] private/protected properties, with[out] getter methods.
           * @author Adrian Testa-Avila <AT@custom-anything.com>
           * @copyright 2012
           * @license CC/BY-SA <http://creativecommons.org/licenses/by-sa/3.0/>
           */
          trait READONLY{
          
          ##  NONPUBLIC PROPERTIES  ##
          
          /** 
           * @property array [private]$_readonly
           *
           * list of private/protected properties to be readable.
           *
           * if set, only listed properties will be readable;
           * otherwise, all private/protected properties will be readable.
           */
          
          ##  PUBLIC METHODS  ##
          
          /**
           * attempts to read an inaccessible property.
           *
           * first checks if a getter method exists, 
           * otherwise, attempts to read the property directly.
           *
           * @return mixed                value of property if readable; false otherwise.
           */
          public function __get( $name ){
              // is there a getter method?
              if( method_exists( $this,('get'.$name) ) ){
                  return $this->{'get'.$name}();
              }
              // if the property exists, is reading allowed?
              if( (!isset( $this->_readonly ) || in_array( $name,$this->_readonly )) ){
                  // check defined readonly properties
                  if( isset( $this->$name ) ){ return $this->$name; }
              }
              // no love
              return false;
          }
          
          /**
           * @method mixed get*()     dynamic getter method for object property *.
           * @used-by READONLY::__get()
           */
          
          }
            traq;11019379 wrote:

            I've had a "readonly" __get() method for some time; I turned it into a trait when I started running PHP 5.4:

            /** 
             * allows "read-only" access to [specified] private/protected properties, with[out] getter methods.
             * @author Adrian Testa-Avila <AT@custom-anything.com>
             * @copyright 2012
             * @license CC/BY-SA <http://creativecommons.org/licenses/by-sa/3.0/>
             */
            trait READONLY{
            
            ##  NONPUBLIC PROPERTIES  ##
            
            /** 
             * @property array [private]$_readonly
             *
             * list of private/protected properties to be readable.
             *
             * if set, only listed properties will be readable;
             * otherwise, all private/protected properties will be readable.
             */
            
            ##  PUBLIC METHODS  ##
            
            /**
             * attempts to read an inaccessible property.
             *
             * first checks if a getter method exists, 
             * otherwise, attempts to read the property directly.
             *
             * @return mixed                value of property if readable; false otherwise.
             */
            public function __get( $name ){
                // is there a getter method?
                if( method_exists( $this,('get'.$name) ) ){
                    return $this->{'get'.$name}();
                }
                // if the property exists, is reading allowed?
                if( (!isset( $this->_readonly ) || in_array( $name,$this->_readonly )) ){
                    // check defined readonly properties
                    if( isset( $this->$name ) ){ return $this->$name; }
                }
                // no love
                return false;
            }
            
            /**
             * @method mixed get*()     dynamic getter method for object property *.
             * @used-by READONLY::__get()
             */
            
            }

            This looks pretty good actually, trait definitely has its usage. Unfortunately most webhosts and applications have yet to support PHP 5.4, and for this reason trait cannot be widely used in designing your software. Different story though if you are not developing an application, but an individual site for yourself or your company.

            And I was wondering though. Does PHP's namespace system support importing of an entire namespace? I mean, assuming you have a namespace Model with several subnamespace (user, message for instance). Can you import an entire namespace Model in another namespace Controller like this:

            namespace Controller;
            use Model;
            
            $member = new Member;
            // equivalent to: $member = new Model\User\Member;
            
            $message = new PrivateMessage;
            // equivalent to: $message = new Model\Message\PrivateMessage;
            

            or you have to import each subnamespaces one by one?

            namespace Controller;
            
            use Model\User;
            use Model\Message;
            
            $member = new Member;
            // equivalent to: $member = new Model\User\Member;
            
            $message = new PrivateMessage;
            // equivalent to: $message = new Model\Message\PrivateMessage;
            

            Just curious, hopefully PHP's namespace can work out just like C#'s namespace and Java's package system.

              You say it hope its implemented like C# but working in C# every day I can tell you that if you d "use Model;" you wouldn't be able to do new Member, you'd instead have to do User.Member (or in PHP User\Member). I don't know if it will do that or not in php as I've never tried. Of course I also do that opposite of you. Instead of doing say Controller\User{classes} and Model\User{classes} I instead do User\Controller{classes} and User\Model{Classes} and that way my modules are separated, and I can easily add or remove modules from a customers product.

              Also, as far as not being able to use traits because they are not widely available. I'd have to disagree but maybe that's because all my customers are either hosted by me, or I at least set up the hosting environment on AWS. Mainly because I tell them, if you don't let use determine your server settings, we can't verify all components working properly. We do this so we don't have to build for acceptance in any possible environment, but instead we have control over where and how it will be deployed meaning less development time wasted on making it compatible across systems.

                5.4 is available on my host, and I've seen it available on others.

                As for those that don't have it available, I am unapologetic.

                  Derokorian;11019505 wrote:

                  You say it hope its implemented like C# but working in C# every day I can tell you that if you d "use Model;" you wouldn't be able to do new Member, you'd instead have to do User.Member (or in PHP User\Member). I don't know if it will do that or not in php as I've never tried. Of course I also do that opposite of you. Instead of doing say Controller\User{classes} and Model\User{classes} I instead do User\Controller{classes} and User\Model{Classes} and that way my modules are separated, and I can easily add or remove modules from a customers product.

                  I see, guess you just have to import classes in a way like this below in order to use their short-hand names?

                  use Model\User\Member;
                  use Model\Message\PrivateMessage;
                  
                  $user = new Member;
                  $message = new PrivateMessage;
                  

                  Seems kinda tedious to me, especially when you have a factory type of user generator that creates user object dynamically and do not know whether its gonna be a member, an admin, a banned user or a guest to begin with. Is there really no way to import an entire namespace? I remember in Java you can use the syntax import javax.swing.* to obtain an entire package. This cannot be done in C# and PHP?

                    I wouldn't imagine so, since part of the point of namespacing is to prevent collisions. However it is importing the entire namespace, but not sub namespaces (aka its not recursive). This makes sense. If you had the following:

                    Application\User\Controller\class Admin
                    Application\User\Model\class Admin
                    Application\User\class Admin

                    Say you then typed

                    use Application\User; 
                    $var = new Admin();
                    

                    If it recursively included all classes in any depth of hierarchy within the structure, how do you know which admin class you're instantiating? However since its not recursive, you know that you just instantiated an instance of Application\User\class Admin.

                    Edit: Also in your example, it would only make sense to do that if the structure was:
                    Model\User\Member\class Member
                    Model\Message\PrivateMessage\class PrivateMessage

                    Why? Because you USE the namespace and instantiate the class, so unless in your example both classes were in a namespace of the same name it doesn't make sense to even try to do that.

                      Derokorian;11019519 wrote:

                      I wouldn't imagine so, since part of the point of namespacing is to prevent collisions. However it is importing the entire namespace, but not sub namespaces (aka its not recursive). This makes sense. If you had the following:

                      Application\User\Controller\class Admin
                      Application\User\Model\class Admin
                      Application\User\class Admin

                      Say you then typed

                      use Application\User; 
                      $var = new Admin();
                      

                      If it recursively included all classes in any depth of hierarchy within the structure, how do you know which admin class you're instantiating? However since its not recursive, you know that you just instantiated an instance of Application\User\class Admin.

                      Edit: Also in your example, it would only make sense to do that if the structure was:
                      Model\User\Member\class Member
                      Model\Message\PrivateMessage\class PrivateMessage

                      Why? Because you USE the namespace and instantiate the class, so unless in your example both classes were in a namespace of the same name it doesn't make sense to even try to do that.

                      I see, guess I was a bit confused before. Assuming the two subnamespaces User and Message do not contain conflicting class names, the syntax below should be perfectly legal, right?

                      use Model\User;
                      use Model\Message;
                      
                      $user = new Member; // Member is a class in subnamespace User
                      $message = new PrivateMessage; // PrivateMessage is a class in subnamespace Message
                      

                      And the way you design your class hierarchy(user/model/{classes}, it seems more suitable for HMVC design in which user, message all have their corresponding models, controllers and views.

                        Lord Yggdrasill;11019521 wrote:

                        I see, guess I was a bit confused before. Assuming the two subnamespaces User and Message do not contain conflicting class names, the syntax below should be perfectly legal, right?

                        use Model\User;
                        use Model\Message;
                        
                        $user = new Member; // Member is a class in subnamespace User
                        $message = new PrivateMessage; // PrivateMessage is a class in subnamespace Message
                        

                        This is where use comes in.

                        use \Model\User as MU;
                        use \Model\Message as MM;
                        
                        $user = new MU\Member();
                        $message = new MM\PrivateMessage();
                          traq;11019523 wrote:

                          This is where use comes in.

                          use \Model\User as MU;
                          use \Model\Message as MM;
                          
                          $user = new MU\Member();
                          $message = new MM\PrivateMessage();

                          umm this does not really look much better than using the entire namespace, unless you have a system like this App\Controller\User\Member\MemberProfile\ProfileField or something like that. Cant you just use $user = new Member(); after importing the subnamespace Model\User. And if you dont mind me asking, is there a good reason why there is another right slash '\' right in front of Model?

                            The reason for the leading slash is to start at the root namespace. If you don't, and you're in a namespace then its going to start where you're currently at. IE:

                            namespace 'Application\Modules\User';
                            
                            use Model\Message;
                            
                            $pm = new PrivateMessage(); // Same as saying new \Application\Modules\User\Model\Message\PrivateMessage();
                            
                            // Meanwhile in another file:
                            namespace 'Application\Modules\User';
                            
                            use \Model\Message;
                            
                            $pm = new PrivateMessage(); // Same as saying new \Model\Message\PrivateMessage()
                            

                            I believe traq's point may have been that you can do "use <namespace> as <alias>" as a way of resolving conflicts. Say for example you have the previous example I used with Admin classes. You could then do:

                            use Application\User\Controller as C;
                            use Application\User\Model as M;
                            use Application\User as Base;
                            
                            $AdminController = new C.Admin();
                            $AdminModel = new M.Admin();
                            $AdminBase = new Base.Admin();
                            

                              I see, thanks for making it clear to me. Guess I will have to use the leading right slash all the time then, otherwise it starts in the current namespace and wont be able to find the appropriate class. XD I am not quite familiar with the idea of namespace aliasing yet, but guess it can solve some problems. Will look it up soon.

                              And btw, do you think its a good practice t odesign your namespace system to match your actual directory/file structure? Assume you have directories such as model, controller and so on, in which there are subdirectories like user, message in the directory model, and class files member, admin, banned, guest in subdirectory user. Does this give a good reason to design namespace Model with subnamespace Model\User and Model\Message? Or do you actually prefer having namespaces completely irrelevant to the file structure?

                                I prefer my namespacing and folder structure to be identical, and my file names to match as well; for example:

                                // Application\Core\Traits\trait.Singleton.php
                                namespace \Application\Core\Traits;
                                
                                trait Singleton { }
                                
                                
                                // Application\Core\Base\interface.iModel.php
                                namespace \Application\Core\Base;
                                
                                interface iModel { }
                                
                                
                                // Application\Modules\User\Model\class.UserModel.php
                                namespace \Application\Modules\User\Model;
                                
                                use \Application\Core\Base;
                                
                                class UserModel implements iModel { }

                                I think it just comes down to one of personal preference or company policy.

                                  Derokorian;11019539 wrote:

                                  I prefer my namespacing and folder structure to be identical, and my file names to match as well; for example:

                                  // Application\Core\Traits\trait.Singleton.php
                                  namespace \Application\Core\Traits;
                                  
                                  trait Singleton { }
                                  
                                  
                                  // Application\Core\Base\interface.iModel.php
                                  namespace \Application\Core\Base;
                                  
                                  interface iModel { }
                                  
                                  
                                  // Application\Modules\User\Model\class.UserModel.php
                                  namespace \Application\Modules\User\Model;
                                  
                                  use \Application\Core\Base;
                                  
                                  class UserModel implements iModel { }

                                  I think it just comes down to one of personal preference or company policy.

                                  I understand, thats a really good point. Designing your namespace system based on folder structure also makes it easier for autoloaders, doesnt it?

                                    Lord Yggdrasill;11019543 wrote:

                                    Designing your namespace system based on folder structure also makes it easier for autoloaders, doesnt it?

                                    Yes; that's what I was going to say.

                                    traq;11019523 wrote:

                                    This is where use comes in.

                                    *use as. (sorry!)

                                    Actually, we've all been doing it wrong. I double-checked. Aliasing the namespace is pretty much required.

                                    Observe:

                                    <?php
                                    namespace one{
                                        function hello(){ print "hello"; }
                                    }
                                    namespace two{
                                        use \one;
                                    
                                    hello();
                                    # Outputs:
                                    # > Fatal error: Call to undefined function two\hello()
                                    }

                                    Whereas:

                                    <?php
                                    namespace one{
                                        function hello(){ print "hello"; }
                                    }
                                    namespace two{
                                        use \one as o;
                                    
                                    o\hello();
                                    # Outputs:
                                    # > hello
                                    }

                                    Or:

                                    <?php
                                    namespace one{
                                        function hello(){ print "hello"; }
                                    }
                                    namespace two{
                                    # Note: no `use` statement
                                    
                                    \one\hello();
                                    # Outputs:
                                    # > hello
                                    }

                                    And of Course:

                                    <?php
                                    namespace one{
                                        function mysql_connect( $h,$u,$p ){ print "Stop using the mysql_*() functions!"; }
                                    }
                                    namespace one\another{
                                        mysql_connect( 'host','user','pass' );
                                    # there is no one\another\mysql_connect(),
                                    # so PHP falls back on the root namespace
                                    # (_not_ `\one`, but `\` )
                                    # and the "real" mysql_connect() function.
                                    }
                                    

                                    namespaces are less like [font=monospace]include[/font] and more like a filesystem: you want the functions in [font=monospace]\my\php\stuff[/font], not the ones in the root (PHP's default) namespace.

                                      traq;11019553 wrote:

                                      Yes; that's what I was going to say.

                                      *use as. (sorry!)

                                      Actually, we've all been doing it wrong. I double-checked. Aliasing the namespace is pretty much required.

                                      Observe:

                                      <?php
                                      namespace one{
                                          function hello(){ print "hello"; }
                                      }
                                      namespace two{
                                          use \one;
                                      
                                      hello();
                                      # Outputs:
                                      # > Fatal error: Call to undefined function two\hello()
                                      }

                                      Whereas:

                                      <?php
                                      namespace one{
                                          function hello(){ print "hello"; }
                                      }
                                      namespace two{
                                          use \one as o;
                                      
                                      o\hello();
                                      # Outputs:
                                      # > hello
                                      }

                                      Or:

                                      <?php
                                      namespace one{
                                          function hello(){ print "hello"; }
                                      }
                                      namespace two{
                                      # Note: no `use` statement
                                      
                                      \one\hello();
                                      # Outputs:
                                      # > hello
                                      }

                                      namespaces are less like [font=monospace]include[/font] and more like a filesystem: you want the functions in [font=monospace]\my\php\stuff[/font], not the ones in the root (PHP's default) namespace.

                                      umm so you have to write $member = new User\Member; even if you have imported the subnamespace? Oh my this is bad, kills the purpose of using Namespace... Well if theres still one left it may be easy autoloading...

                                        I don't think it's "bad." It's just serving a different purpose than you had thought.

                                        You're not "importing" the namespace, you're just declaring a shortcut for using it. For example:

                                        You and I share a computer and are both looking for jobs. To this end, we both write resumes, and it happens that we both name our files [font=monospace]resume[/font]. Fortunately, we are "power users" and know better than to save all of our files on the desktop: we save them in our own respective directories.

                                        • From inside your directory, you can open your resume directly by asking for [font=monospace]resume[/font].

                                        • However, from the desktop, you'd have to type [font=monospace]Yggdrasill\resume[/font].

                                        • From my directory, you'd have to add the root to the path: [font=monospace]\Yggdrasill\resume[/font], or else the computer would be looking for [font=monospace]\traq\Yggdrasill\resume[/font], which doesn't exist.

                                        Now suppose you have a really long namespace - obviously, aliasing that namespace is still a significant advantage, even if we can't use it "automagically":

                                        <?php
                                        use \my\PHP\scripts\databases\mysql\object_models\class as M;