SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 36
  1. #1
    SitePoint Evangelist
    Join Date
    May 2006
    Location
    Austin
    Posts
    401
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    Getters and Setters, what do you normally do

    I've been having an internal debate about the manner in using getter and setter method pairs, vs, using a set property and just a setter method.

    Grossly simplified, basically:

    PHP Code:

    class getters 
    {
    private 
    $name false;

    function 
    setName($name)
    {
    $this->name $name;
    }


    or...

    PHP Code:

    class getters_setters
    {

    function 
    setName($name)
    {
    $this->name $name;
    }

    function 
    getName()
    {
    return 
    $this->name;
    }


    I've been sort of annoyed by having a ton of seemingly unnecessary methods lying around, when the first example works fine for most purposes I've run into. In this case, the class isn't being extended. The only difference within the class is that I would access the variable via $this->name vs. $this->getName().

    Anyway, is there a best practice way to do this, or would it be dependent on whether I'm going to extent the class or not?
    Merchant Equipment Store - Merchant Services, POS, Equipment, and supplies.
    Merchant Account Blog | Ecommerce Blog

  2. #2
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,011
    Mentioned
    56 Post(s)
    Tagged
    0 Thread(s)
    Look into the magic __get and __set functions.

  3. #3
    SitePoint Evangelist
    Join Date
    May 2006
    Location
    Austin
    Posts
    401
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Why I didn't remember those, ugh...

    Thanks
    Merchant Equipment Store - Merchant Services, POS, Equipment, and supplies.
    Merchant Account Blog | Ecommerce Blog

  4. #4
    SitePoint Evangelist
    Join Date
    Aug 2005
    Location
    Winnipeg
    Posts
    498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Matter of personal choice I think...some people swear by publically accessibl properties...myself...I use nothing but getter/setters except when implementing a data mapper or similar object, in that case I make the exception.
    The only constant in software is change itself

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Partially subjective and partially contextual, this is a rather hard question to answer in the abstract. If your objects has a lot of accessors, it could be a sign of your code having a low coherence. If you can ignore the inflammatory title, this is a good text about that matter.

  6. #6
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    The only reason I've ever found found for getters/setters is if you're writing a class and you have read only properties.

    Really php needs to support something like "public readonly $property;" parts of the manual already implies this is should possible

  7. #7
    SitePoint Evangelist
    Join Date
    May 2006
    Location
    Austin
    Posts
    401
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    My biggest concern is that these bypass private and protected and essentially make all properties public. Also, it makes validating or formatting basically impossible. You can do it when you need to use the property, but not when you set the property.

    Normally, I wouldn't consider using them, but I've got an integration with a nasty API that allows for 300+ user variables. Creating manual getters and setters ends up with about 1200 (uncommented) lines of code just for those.

    On the other side, that's a lot of potential input to lose track of. I'm not too keen on the obscurity that __get and __set create.
    Merchant Equipment Store - Merchant Services, POS, Equipment, and supplies.
    Merchant Account Blog | Ecommerce Blog

  8. #8
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,011
    Mentioned
    56 Post(s)
    Tagged
    0 Thread(s)
    What's so obscure about them? They are invoked upon any attempt to access an inaccessible variable from outside the class, or any attempt to access a non-existent member of a class.

  9. #9
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,047
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    I would opt for something like the below.

    PHP Code:
    interface Overloadable {
        public function 
    setAttr($name,$value);
        public function 
    getAttr($name);
        public function 
    hasAttr($name);
    }

    class 
    Foo implements Overloadable {

        private 
    $attr;
        
        public function 
    __construct() {
            
    $this->attr = array();
        }
        
        public function 
    setAttr($name,$value) {
            
    $this->attr[$name] = $value;
        }
        
        public function 
    getAttr($name) {
            if(
    $this->hasAttr($name)) {
                return 
    $this->attr[$name];
            } else {
                throw new 
    Exception('Attribute '.$name.' doesn\'t exist.');
            }
        }
        
        public function 
    hasAttr($name) {
            return 
    array_key_exists($name,$this->attr);
        }



  10. #10
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by oddz View Post
    I would opt for something like the below.

    PHP Code:
    interface Overloadable {
        public function 
    setAttr($name,$value);
        public function 
    getAttr($name);
        public function 
    hasAttr($name);
    }

    class 
    Foo implements Overloadable {

        private 
    $attr;
        
        public function 
    __construct() {
            
    $this->attr = array();
        }
        
        public function 
    setAttr($name,$value) {
            
    $this->attr[$name] = $value;
        }
        
        public function 
    getAttr($name) {
            if(
    $this->hasAttr($name)) {
                return 
    $this->attr[$name];
            } else {
                throw new 
    Exception('Attribute '.$name.' doesn\'t exist.');
            }
        }
        
        public function 
    hasAttr($name) {
            return 
    array_key_exists($name,$this->attr);
        }


    Is there any reason in this case for using an interface and not an abstract class? Most classes which will implement that will have to repeat the exact same code.

    Also, I'd replace getAttr() with __get(), setAttr() with __set() and hasAttr() with __isset().

  11. #11
    SitePoint Evangelist
    Join Date
    May 2006
    Location
    Austin
    Posts
    401
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Michael Morris View Post
    What's so obscure about them? They are invoked upon any attempt to access an inaccessible variable from outside the class, or any attempt to access a non-existent member of a class.
    The obscurity is that you can no longer trust private or protected methods. They all become public. Seems a step backwards the php wouldn't integrate errors into trying to set a private property through the __set method...
    Merchant Equipment Store - Merchant Services, POS, Equipment, and supplies.
    Merchant Account Blog | Ecommerce Blog

  12. #12
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,047
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    Quote Originally Posted by TomB
    Is there any reason in this case for using an interface and not an abstract class?
    The magical methods will be slower. That may not be much of a concern.

    However, I also find programming to a interface results in more maintainable and readable code. Magical methods while nice are a little on the messy side in my opinion.

    A abstract class could be used as a template. I was just providing a basic idea though through the example.

  13. #13
    SitePoint Evangelist
    Join Date
    May 2006
    Location
    Austin
    Posts
    401
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    I wrote this up in the past few minutes. It will prevent getting and setting private properties.

    This is a messy hack, so if anyone knows a more efficient way of doing this, let me know. I have not found a single example of another way to do this.

    PHP Code:

    <?php

    class test 
    {
        
        private 
    $current_page;
        private 
    $private_properties = array();
        
        private 
    $name NULL;
        public 
    $age NULL;
        
        public function 
    __construct()
        {
            
            
    $class = new ReflectionClass(__CLASS__);
            
    $this->current_page $class->getFileName();
            
            
    $class_properties get_class_vars(__CLASS__);
            
            foreach(
    $class_properties as $class_property_name => $property_value)
            {
                
    $prop = new ReflectionProperty(__CLASS__$class_property_name);
                
                if(
    $prop->isPrivate() || $prop->isProtected())
                {
                    
    $this->private_properties[] = $prop->getName();
                }
            }
        }
        
        public function 
    __set($var$val)
        {
            
    $requesting_page debug_backtrace();
            
            if(
    $requesting_page[0]['file'] != $this->current_page)
            {
                if(
    in_array($var,$this->private_properties))
                {
                    
                    
    trigger_error("Cannot access private property ".__CLASS__."::".$var." in ".$requesting_page[0]['file']."on line "$requesting_page[0]['line'],E_USER_ERROR);
                
                }
            }
                
            
    $this->$var $val;
        }
        
        public function 
    __get($var)
        {
            
            
    $requesting_page debug_backtrace();
            
            if(isset(
    $this->$var)){
                
                if(
    $requesting_page[0]['file'] != $this->current_page)
                {
                    if(
    in_array($var,$this->private_properties))
                    {
                        
                        
    trigger_error("Cannot access private property ".__CLASS__."::".$var." in ".$requesting_page[0]['file']."on line "$requesting_page[0]['line'],E_USER_ERROR);
                    
                    }
                }
                
                return 
    $this->$var;
                
            } else {
                
                throw new 
    Exception("Required property [" $var "] has not been set!");
                    
            }
        }
    }
    Will throw a fatal error if you try getting or setting a private or protected property from outside the class.
    Merchant Equipment Store - Merchant Services, POS, Equipment, and supplies.
    Merchant Account Blog | Ecommerce Blog

  14. #14
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    Really php needs to support something like "public readonly $property;" parts of the manual already implies this is should possible
    That's due to DOMNode being implemented in C. They're magic and do things you wouldn't expect of PHP code.

  15. #15
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Of course, but it implies it may be something they'll implement in future.

  16. #16
    SitePoint Addict been's Avatar
    Join Date
    May 2002
    Location
    Gent, Belgium
    Posts
    284
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This construct just crossed my mind:
    PHP Code:
    class FooBarThingie
    {
        
    // visibility keywords are for sissies ;-)
        
    var $_foo;
        var 
    $_bar;

        function 
    __construct($foo$bar)
        {
            
    $this->_foo $foo;
            
    $this->_bar $bar;
        }

        
    // property
        
    function foo()
        {
            if (
    func_num_args() == 1) {
                
    $this->_foo func_get_arg(0);
                return 
    $this;
            }
            return 
    $this->_foo;
        }

        
    // read-only property
        
    function bar()
        {
            return 
    $this->_bar;
        }

    The 'property' violates single responsibility principle as well as LSP, but it does this in favour of uniform access principle and fluent interface. Can't decide if it's a good idea though.
    Per
    Everything
    works on a PowerPoint slide

  17. #17
    SitePoint Guru
    Join Date
    Oct 2006
    Location
    Queensland, Australia
    Posts
    852
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by been View Post
    This construct just crossed my mind:
    Wouldn't something like this be more practical, flexible and cleaner?

    PHP Code:
    <?php
    class Example
    {
        public 
    $foo;
        public 
    $bar;
        public 
    $baz;

        
    // Property
        
    function property($prop$value null)
        {
            
    $property['foo'] = 'get';
            
    $property['bar'] = 'get/set';
            
    $property['baz'] = 'set';

            if(isset(
    $property[$prop]))
            {
                
    // Get value
                
    if($value === null)
                {
                    if(
    $property[$prop] == 'get' || $property[$prop] == 'get/set') {
                        return 
    $this->$prop;
                    } else {
                        echo 
    'Restricted';
                    }
                }
                
    // Set value
                
    else
                {
                    if(
    $property[$prop] == 'set' || $property[$prop] == 'get/set') {
                        
    $this->$prop $value;
                        return 
    true;
                    } else {
                        echo 
    'Restricted';
                    }
                }
            }
            else
            {
                echo 
    "Property doesn't exist";
            }

            return 
    false;
        }
    }
    ?>

  18. #18
    SitePoint Guru
    Join Date
    Oct 2006
    Location
    Queensland, Australia
    Posts
    852
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    By the way, here's the above code, but with a little additional code to allow the getting and setting of public properties only.

    PHP Code:
    <?php
    class Example
    {
        public 
    $foo;
        public 
    $bar;
        public 
    $baz;

        
    // Property
        
    function property($prop$value null)
        {
            
    $property['foo'] = 'get';
            
    $property['bar'] = 'get/set';
            
    $property['baz'] = 'set';

            if(isset(
    $property[$prop]))
            {
                
    $reflection = new ReflectionProperty(__CLASS__$prop);

                
    // Get value
                
    if($value === null)
                {
                    if((
    $property[$prop] == 'get' || $property[$prop] == 'get/set') && $reflection->isPublic() == true) {
                        return 
    $this->$prop;
                    } else {
                        echo 
    'Restricted';
                    }
                }
                
    // Set value
                
    else
                {
                    if((
    $property[$prop] == 'set' || $property[$prop] == 'get/set') && $reflection->isPublic() == true) {
                        
    $this->$prop $value;
                        return 
    true;
                    } else {
                        echo 
    'Restricted';
                    }
                }
            }
            else
            {
                echo 
    "Property doesn't exist";
            }
        }
    }
    ?>

  19. #19
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    You could always abuse the protected visibility keyword a little, this makes more sense to me.
    PHP Code:
    <?php
    class Classroom
    {
        protected
            
    $teacher,
            
    $room;
            
        public function 
    __construct($teacher$room)
        {
            
    $this->teacher    $teacher;
            
    $this->room        $room;
        }
            
        public function 
    __get($key)
        {
            return 
    $this->{$key};
        }
        
        public function 
    __set($key$value)
        {
            
    $reflection = new ReflectionClass($this);
            if(
    true === $reflection->hasProperty($key) && true === $reflection->getProperty($key)->isProtected())
            {
                throw new 
    Exception(sprintf('%s is a read only property.'$key));
            }
        }
    }

    $class = new Classroom('Mrs.Peacock''4B');
    echo 
    $class->teacher#Mrs.Peacock
    try
    {
        
    $class->teacher 'Mrs.Carter'#teacher is a read only property.
    }
    catch(
    Exception $exception)
    {
        echo 
    $exception->getMessage();
    }
    ?>
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  20. #20
    SitePoint Guru
    Join Date
    Jan 2005
    Location
    heaven
    Posts
    953
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You can always go over board and use __call() to create your public assessor functions.

    PHP Code:
    class Foo
    {
        protected 
    $_bar;
        
        public function 
    __call($name$arguments)
        {
            if( 
    $name == 'setBar' ){
                
    $this->_bar $arguments;
                return 
    true;
            }
            
            if( 
    $name == 'getBar' ) {
                return 
    $this->_bar;
            }
        }

    Creativity knows no other restraint than the
    confines of a small mind.
    - Me
    Geekly Humor
    Oh baby! Check out the design patterns on that framework!

  21. #21
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I’m a Scot. As we know Scotsmen all wear kilts and, for better or worse, there is a great deal of interest in what we wear underneath. Now, if you met me, I’m sure you’d ask politely using my public ear interface. You wouldn’t just hoik up my kilt and have a good old rummage around, leaving me exposed to the inclement Scottish summer.

    I sort of feel the same way about direct property access.

  22. #22
    SitePoint Evangelist
    Join Date
    Jun 2003
    Location
    Melbourne, Australia
    Posts
    440
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by McGruff View Post
    You wouldn’t just hoik up my kilt and have a good old rummage around, leaving me exposed to the inclement Scottish summer.
    Off Topic:

    My most immediate concern would be the rummaging, not the inclement summer.
    Zealotry is contingent upon 100 posts and addiction 200?

  23. #23
    SitePoint Addict been's Avatar
    Join Date
    May 2002
    Location
    Gent, Belgium
    Posts
    284
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    __get, __set and __call are only called if a property or method is missing. It just feels strange abusing them for stuff that IS supposed to be there. It also seems that they very quickly get overly verbose to write, especially taking into account visibility (if you want)
    Also objects of such classes are no longer very useful reflection candidates.


    Now that I've thought a little bit more about it and seeing all these __get/set/call stuff, I'm still liking my (not yet used in practice) approach. The interface stays explicit and it brings a uniform access to both methods and properties. It doesn't do mixed visibility, it would be tied to the visibility of the function, but then again, I'm not too keen on all this different visibility stuff. I have use this approach and it has served me well over the years:
    - instance / class variables are considered private, except for classes in the same file. I do not use a visibility keyword, just prefix them with an underscore. This is to indicate: if you access this, all bets are of! But I do not want other programmers to go through a lot of trouble should they actually need access to them.
    - Same goes for methods with an underscore prefix.

    The approach substitutes property access with a method call, which carries a performance penalty, but I have not benchmarked how big of a penalty. I do suspect that it will be less than all the missing-property/method/reflection constructs. I also do not feel comfy about the LSP and SRP violations.
    Last edited by been; Aug 20, 2009 at 06:02. Reason: added LSP and SRP violation
    Per
    Everything
    works on a PowerPoint slide

  24. #24
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I keep reading that you should NOT use __get and __set, because they slow, they X and they Y... But I can't find a good enough reason NOT to use them.

    I always have something similar to this:
    PHP Code:

    /**
     * Sample class to hold some data.
     * 
     * @property string $field_1 The first test field.
     * @property string $field_2 The second test field.
     * @property string $field_3 The third test field.
     * @property myOtherObject $field_4 The fourth test field, that represents some other class.
     */
    class myObject {
        
        
    /**
         * Array that holds what data can be stored in this object.
         */
        
    private $_data = array(
            
    'field_1' => 'default_1',
            
    'field_2' => 'default_2',
            
    'field_3' => 'default_3',
            
    'field_4' => null,
        );
        
        
    /**
         * Initializes the class
         */
        
    public function __constructor() {
            
    $this->_data ['field_4'] = new myOtherObject('5');        
        }
        
        
    /**
         * Magically gets a value.
         * 
         * @param $key The key of the value to return.
         * @return whatever was set to that key.
         */
        
    public function __get($key) {
            
    // Return the value if set
            
    if (isset($this->_data$key ]) ) {
                return 
    $this->_data$key ];
            }
            
    // Throw an exception if the field is not expected
            
    throw new Exception("Unknown field [$key] on get.");
        }
        
        
    /**
         * Magically sets a value.
         * 
         * @param $key The key to set the value to.
         * @param $value The value to set
         */
        
    public function __set($key$value) {
            
    // Return the value if set
            
    if (isset($this->_data$key ]) ) {
                
    $this->_data$key ] = $value;
            }
            
    // Throw an exception if the field is not expected
            
    throw new Exception("Unknown field [$key] on set.");
        }

    The "@property" documentation makes sure that my properties are not "hidden", and is respected by all good IDEs (ones you should use anyway).

    The reason I like dooing it like this, is this:
    PHP Code:
    $foo = new myObject();
    $foo->field_1 5;
    $foo->field_4->property_6 'bar';
    $foo->field_4->property_7->object_2->title 'bob'
    Instead of:
    PHP Code:
    $foo = new myObject();
    $foo->setField_1(5);
    $foo->getField_4()->setProperty_6('bar'); // I know this does not work sometimes
    $foo->getField_4()->getProperty_7()->getObject_2()->setTitle('bob'); // I know this does not work sometimes 

  25. #25
    SitePoint Guru
    Join Date
    Jan 2005
    Location
    heaven
    Posts
    953
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Thumbs up

    Quote Originally Posted by McGruff View Post
    I’m a Scot. As we know Scotsmen all wear kilts and, for better or worse, there is a great deal of interest in what we wear underneath. Now, if you met me, I’m sure you’d ask politely using my public ear interface. You wouldn’t just hoik up my kilt and have a good old rummage around, leaving me exposed to the inclement Scottish summer.

    I sort of feel the same way about direct property access.
    Off Topic:


    I haven't slept for almost 24 hours and thats like the most amazing thing I've ever read! Thumbs up!
    Creativity knows no other restraint than the
    confines of a small mind.
    - Me
    Geekly Humor
    Oh baby! Check out the design patterns on that framework!


Bookmarks

Posting Permissions

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