SitePoint Sponsor

User Tag List

View Poll Results: How do you implement properties?

Voters
41. You may not vote on this poll
  • Java style: getFoo(), setFoo($value)

    23 56.10%
  • Obj-C style: foo(), setFoo($value)

    0 0%
  • Php's magic methods: __get() and __set()

    9 21.95%
  • No getters/setters, just plain old properties

    7 17.07%
  • Other

    2 4.88%
Page 2 of 3 FirstFirst 123 LastLast
Results 26 to 50 of 51
  1. #26
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by champ View Post
    Is anyone employing this usage of __set or the other magic methods in order to eliminate get_*, or set_* methods, even those dynamically called by the __call magic method?
    I tried it but I don't use it anymore because of the boilerplate code and the lack of a proper way of documenting this behaviour (which is my main beef with __set/__get anyway).
    Design patterns: trying to do Smalltalk in Java.
    I blog too, you know.

  2. #27
    SitePoint Addict
    Join Date
    Jun 2005
    Posts
    262
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    For those that say they prefer the Java style, are you coding actual get*, set* methods in your classes or are you faking it with a __call magic method which sniffs for method names starting with get* or set*?

  3. #28
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by champ View Post
    Is anyone employing this usage of __set or the other magic methods in order to eliminate get_*, or set_* methods, even those dynamically called by the __call magic method?

    That's exactly what I'm doing, although I go one step further by doing this:

    PHP Code:
        public function __call($name$arguments) {
            if (
    preg_match('/get(.*)/'$name$matches)) {
                return 
    $this->__get(lcfirst($matches[1]));
            }

            if (
    preg_match('/set(.*)/'$name$matches)) {
                return 
    $this->__set(lcfirst($matches[1]), $arguments[0]);
            }
        } 
    which means that you can access the properties via methods, making it more symmetrical.

    My original intent on starting this thread was to post some code that does this, but I'm still working out some things...
    Last edited by 33degrees; Aug 28, 2007 at 14:32. Reason: bad closing tag

  4. #29
    SitePoint Addict
    Join Date
    Jun 2005
    Posts
    262
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees View Post
    That's exactly what I'm doing, although I go one step further by doing this
    33degrees, it appears your implementation allows for setting and returning properties in two ways:

    Code:
    $object->setName('John');
    echo $object->getName();
    or
    Code:
    $object->name = 'John';
    echo $object->name;
    Either approach does the same thing. If this is what you're doing, which of the above did you choose to use in your code? Or do you use a mixture?

  5. #30
    PHP/Rails Developer Czaries's Avatar
    Join Date
    May 2004
    Location
    Central USA
    Posts
    806
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees View Post
    That's exactly what I'm doing, although I go one step further by doing this:

    PHP Code:
        public function __call($name$arguments) {
            if (
    preg_match('/get(.*)/'$name$matches)) {
                return 
    $this->__get(lcfirst($matches[1]));
            }

            if (
    preg_match('/set(.*)/'$name$matches)) {
                return 
    $this->__set(lcfirst($matches[1]), $arguments[0]);
            }
        } 
    What benefit does this have over accessing the properties directly? Now you've added the overhead of loading the PCRE engine just to access a flat variable, all for the sake of a preference in syntax. The functions still do no processing or business logic on the data, so there is no point in having them. Creating something like this just makes your code harder to read and maintain. Why don't you just utilize the tools provided to you by the language itself and skip all the extra overhead and "magic" functions?

  6. #31
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by champ View Post
    33degrees, it appears your implementation allows for setting and returning properties in two ways:

    Code:
    $object->setName('John');
    echo $object->getName();
    or
    Code:
    $object->name = 'John';
    echo $object->name;
    Either approach does the same thing. If this is what you're doing, which of the above did you choose to use in your code? Or do you use a mixture?
    I prefer the property syntax, because the syntax better communicates intent (plus, I find setter methods like setName('John') to be ugly); I allow both approaches to ensure proper encapsulation, as it completely hides the implementation details. As odd as it might seem, this is similar to the approach used in other languages like eiffel and ruby, where the property access syntax is just syntactical sugar for the methods that do the work.

  7. #32
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Czaries View Post
    What benefit does this have over accessing the properties directly? Now you've added the overhead of loading the PCRE engine just to access a flat variable, all for the sake of a preference in syntax. The functions still do no processing or business logic on the data, so there is no point in having them.
    Because the property might not always just be a flat variable. Data models change, and sometimes things that used to be just a variable need to be processed.

    Quote Originally Posted by Czaries View Post
    Creating something like this just makes your code harder to read and maintain. Why don't you just utilize the tools provided to you by the language itself and skip all the extra overhead and "magic" functions?
    Because, funnily enough, it makes the code easier to maintain. Working with the magic methods has simplified my development; I wouldn't be doing it otherwise.

  8. #33
    SitePoint Addict
    Join Date
    Jun 2005
    Posts
    262
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Much of the discussion so far has assumed that the properties are predefined. What about classes where properties are not?

    For example, let's say I wanted to create a wrapper class for the $_SESSION and $_POST arrays.
    PHP Code:
    class Request
    {
        protected 
    $data = array();
    }

    class 
    Session extends Request
    {
        public function 
    __construct()
        {
            
    $this->data =& $_SESSION;
        }
    }

    class 
    Post extends Request
    {
        public function 
    __construct()
        {
            
    $this->data =& $_POST;
        }

    How do you propose setting and getting variables for the above? How would you check for the existence of variables. How would you remove them?

    You could still implement the __set, __get, __isset, __unset magic methods to set, get, check, and remove data.

    You could also implement the __call magic method to fake set_* and get_*.

    Or you could force yourself to abide by a strict interface without employing any magic methods:
    PHP Code:
    class Request
    {
        public function 
    has($key)
        {
            return 
    array_key_exists($key$this->data);
        }

        public function 
    set($key$value)
        {
            
    $this->data[$key] = $value;
        }

        public function 
    get($key)
        {
            return 
    $this->has($key) ? $this->data[$key] : null;
        }

        public function 
    del($key)
        {
            unset(
    $this->data[$key]);
        }

    I'm wondering if a consistent implementation can be achieved.

  9. #34
    SitePoint Addict
    Join Date
    Jun 2005
    Posts
    262
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here are two interesting articles that are worth a read:
    http://javadude.com/articles/accessors.html
    http://javadude.com/articles/reuse.html

  10. #35
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    To begin with the poll was 80% for method access. Could be better - but not too bad. Since then it's slid down steadily. 70%. 60%. Now it's almost 50% and I'm in despair. Every time you $foo->bar an angel dies in heaven. Monsters.

  11. #36
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by McGruff View Post
    Every time you $foo->bar an angel dies in heaven. Monsters.
    What exactly are the drawbacks of $foo->someNoun compared to $foo->someVerb() in terms of having transparent and uniform class interface?

    All the methods like getName() do is overcome the limitations of the programming language, but the interface should be dictated by the problem domain, not by the language. From domain POV the distinction between what object _has_ and what it _does_ is usually quite clear and the interface should reflect it. Ok, in Java it's technically not possible, but php offers such a possibility, why not to use it?

    PHP Code:
    class PropertySheet {
        function 
    _property($access$name$value) {
            if(
    method_exists($this$m $access ucfirst($name)))
                return 
    $this->$m($value);
            if(!
    property_exists($this$name))
                throw new 
    Exception("Cannot $access property '$name'");
            return (
    $access == 'get') ? $this->$name $this->$name $value;
        }
        function 
    __get($name) {
            return 
    $this->_property('get'$namenull);
        }
        function 
    __set($name$value) {
            return 
    $this->_property('set'$name$value);
        }

    The property access method calls a setter/getter if it is defined, otherwise it fallbacks to a member variable with the same name. This is much like how properties work in e.g. actionscript.

    PHP Code:
    class Circle extends PropertySheet {
        protected 
    $radius;
        
        protected function 
    getArea() {
            return 
    pi() * $this->radius 2;
        }
    }

    $c = new Circle;

    $c->radius 10;   # transparent access
    echo $c->area;     # access via getter
    $c->area 25;     # error, neither property not setter defined 

  12. #37
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by champ View Post
    Much of the discussion so far has assumed that the properties are predefined. What about classes where properties are not?

    I think in this example, the best approach would be to use array access, and you'd be able to foreach over the results. However I don't have any problem with using property access in cases where properties are not predefined, as I don't share some people's desire for strict interfaces.

  13. #38
    SitePoint Enthusiast
    Join Date
    Mar 2005
    Posts
    31
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by stereofrog View Post
    PHP Code:
    class Circle extends PropertySheet {
        protected 
    $radius;
        
        protected function 
    getArea() {
            return 
    pi() * $this->radius 2;
        }
    }

    $c = new Circle;

    $c->radius 10;   # transparent access
    echo $c->area;     # access via getter
    $c->area 25;     # error, neither property not setter defined 
    Area looks like a property just like radius, I can set the radius with $c->radius = 10, so my intuition tells me I should be able to set the area with $c->area = 25. However, if you'd done $c->setRadius(10) and $c->getArea(), I might still have expected a $c->setArea(25) to work properly so I'm not sure either is advantageous.

    I imagine some of my discomfort with using properties is that I'm used to looking through the class to see which functions I have available for get* and set*. In the end your code has the same information, I just have to look and see which properties are defined or if there is a setter/getter for it. It's a little more work since there are two places to check, but I imagine I could adapt to it.

    P.S. Why can't I do setArea() and have it calculate my radius for me?

  14. #39
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by stereofrog View Post
    PHP Code:
    class PropertySheet {
        function 
    _property($access$name$value) {
            if(
    method_exists($this$m $access ucfirst($name)))
                return 
    $this->$m($value);
            if(!
    property_exists($this$name))
                throw new 
    Exception("Cannot $access property '$name'");
            return (
    $access == 'get') ? $this->$name $this->$name $value;
        }
        function 
    __get($name) {
            return 
    $this->_property('get'$namenull);
        }
        function 
    __set($name$value) {
            return 
    $this->_property('set'$name$value);
        }

    There is no need to to use property_exists:
    Quote Originally Posted by http://www.php.net/manual/en/language.oop5.overloading.php
    These methods will only be triggered when your object or inherited object doesn't contain the member or method you're trying to access.
    And infact would be dangerous to do so because

    Quote Originally Posted by http://www.php.net/property_exists
    This function checks if the given property exists in the specified class (and if it is accessible from the current scope).
    Which, in this case, is inside the class ($this) and hence would return private properties.

    What should be done (IMO) is the properties that can be accessed directly should be public, others protected/private (with a getter set, protected probably a good idea). If then in the future the property cannot be accessed directly, simply change it's access modifier and write your getters/setters.

    How this would reflect on your current code is the need to remove the property_exists line and change radius to public.
    Last edited by Ryan Wray; Aug 29, 2007 at 11:46.

  15. #40
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees View Post
    Some languages, like ruby, do away with the distinction between properties and methods, and aren't any less OO for it. They tend to be a lot more OO than PHP in many other ways, as well, but that's another discussion.
    I wouldn't say they do away with the distinction, merely the syntax doesn't neccessary make it obvious which is which. Like if a method has no arguments it could look like a property when being called. I am not that familiar with Ruby, so correct me if I am wrong

    Quote Originally Posted by 33degrees View Post
    While it's true that methods should be used for behaviors, I think the need for encapsulation supersedes it. Being true to the object oriented paradigm is highly dependent on the features of your language, and in the case of languages that don't natively support properties, the proper solution is to use methods. In fact, according to OO principles, a stored value in an object is a data member and not a property, properties being a construct that has the same usage syntax as a data member but are implemented like a method; the closest thing that PHP has to that is __get and __set.
    Of course, I don't disagree with you in the slightest. What is the right thing to do in Object Oriented paradigm may not be the best thing to do in a programming language.

    As I go on to say:
    Quote Originally Posted by Me
    In PHP, using the magic methods, if all of a sudden you need to change a property, you can introduce __get and __set then, and backwards compatibility is maintained.
    [..]

    PHP magic methods are not the optimal solution. Implicit getters/setters like in C# would be better. These are pretty easy to emulate though using __get/__set, just remember to have them in every class.
    Which pretty much agree with your sentiments.

    Really, it is this boiler plate code is unattractive. You could inherit from a base class (like stereofrog has shown) or simply copy 'n paste it into every class (or have a template), but it less than ideal. You could probably get funky with Runkit though this would be going to far. :P

    All in all, writing setters/getters that simply do an return/assign a variable isn't all that attractive either. You can end up with a lot more boilerplate code in a lot cases.

    So which is it: boilerplate code or boilerplate code?

  16. #41
    SitePoint Addict
    Join Date
    Jun 2005
    Posts
    262
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    33degrees, does any class that has one or more properties that need to be set or retrieved a candidate for __set and __get methods? Do you have a standard for which class it would be useful for and which is unnecessary or excessive?

  17. #42
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ryan Wray View Post
    I wouldn't say they do away with the distinction, merely the syntax doesn't neccessary make it obvious which is which. Like if a method has no arguments it could look like a property when being called. I am not that familiar with Ruby, so correct me if I am wrong
    In ruby, data members are always private; to access them you need an accessor and a mutator, which look like this:

    Code Ruby:
    class Bar
      def foo
        @foo
      end
      def foo=(f)
        @foo = f
      end
    end

    Fortunately, you don't need to actually write the properties out, as you can call the attr_accessor macro which generates the methods dynamically:

    Code Ruby:
    class Bar
      attr_accessor: foo
    end

    Now, parenthesis are optional when making method calls in ruby, so bar.foo() is the same as bar.foo, and bar.foo=('hello') is the same as bar.foo = 'hello'. In both cases you're making method calls that look like property syntax. Eiffel has a similar mechanism. To me, this is very similar to my magic method code in php, which makes bar.foo the same as bar.getFoo(), and bar.foo = 'hello' the same as bar.setFoo('hello')

    Quote Originally Posted by Ryan Wray View Post
    What is the right thing to do in Object Oriented paradigm may not be the best thing to do in a programming language.
    This is true, especially in a language like PHP that allows for different programming paradigms. But in my experience, ensuring proper encapsulation will always make your code easier to maintain in the long run.



    Quote Originally Posted by Ryan Wray View Post
    Really, it is this boiler plate code is unattractive. You could inherit from a base class (like stereofrog has shown) or simply copy 'n paste it into every class (or have a template), but it less than ideal.
    If you're inheriting from a base class (which is what I do), all the magic is done for you and hidden away, which is highly preferable to writing setters and getters by hand!

  18. #43
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees View Post
    If you're inheriting from a base class (which is what I do), all the magic is done for you and hidden away, which is highly preferable to writing setters and getters by hand!

    It was often discussed here that have such as base class (kind of like Object in Java) might not be a great idea in PHP. I've always kind of been on the fence on the subject. Saying that, I would probably go about it the same way.

    You might run into problems if you need to inherit from a class you don't have control over (external library). That base class won't inherit the magic methods, and you'll either have to manually add them in or revert back to standard setter/getters (which would break the style!). Some might say the first could cause maintenance problems (e.g. What happens if you need to change logic of these magic methods: multiple places to patch), though realistically, it is probably code very unlikely to need changes.

    It's a pity PHP doesn't provide something built-in.

  19. #44
    SitePoint Addict
    Join Date
    Jun 2005
    Posts
    262
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    For those that prefer the Java style set_ and get_, let's say you had the following classes...
    PHP Code:
    class Customer
    {
        protected 
    $wallet;
    }
    class 
    Wallet
    {
        protected 
    $creditcard;
    }
    class 
    CreditCard
    {
        protected 
    $card_number;

    How would you go about quickly setting and retrieving the card number when you have a multi-level object hierarchy, assuming the properties were not public.

    Surely the __set and __get magic methods would make life easier:
    PHP Code:
    $customer = new Customer;
    $customer->wallet = new Wallet;
    $customer->wallet->creditcard = new CreditCard;
    $customer->wallet->creditcard->card_number '1111-2222-3333-4444';
    echo 
    $customer->wallet->creditcard->card_number

  20. #45
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I never use the verbose-ibility keywords public, private and protected (nor the fourth horseman of the anal retentive apocalypse, final). They don't actually do anything; they just sound like they do.

  21. #46
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lftl View Post
    Area looks like a property just like radius, I can set the radius with $c->radius = 10, so my intuition tells me I should be able to set the area with $c->area = 25.
    It's ok to ask a person about his/her name, but you are usually not able to give names to the persons you meet. Having a read-only property is ok, a bit pity that the language doesn't support us on this, but we get to live with it.

  22. #47
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ryan Wray View Post
    What should be done (IMO) is the properties that can be accessed directly should be public, others protected/private (with a getter set, protected probably a good idea).
    Yes, good point. Actually our PropertySheet can be simplified to something like
    PHP Code:
    class PropertySheet {
        function 
    __get($name) {
            return 
    $this->{"get" ucfirst($name)}();
        }
        function 
    __set($name$value) {
            
    $this->{"set" ucfirst($name)}($value);
        }

    Well, fatals are not especially impressive either... but the idea is clear.

  23. #48
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by champ View Post
    For those that prefer the Java style set_ and get_, let's say you had the following classes...
    PHP Code:
    class Customer
    {
        protected 
    $wallet;
    }
    class 
    Wallet
    {
        protected 
    $creditcard;
    }
    class 
    CreditCard
    {
        protected 
    $card_number;

    How would you go about quickly setting and retrieving the card number when you have a multi-level object hierarchy, assuming the properties were not public.

    Surely the __set and __get magic methods would make life easier:
    PHP Code:
    $customer = new Customer;
    $customer->wallet = new Wallet;
    $customer->wallet->creditcard = new CreditCard;
    $customer->wallet->creditcard->card_number '1111-2222-3333-4444';
    echo 
    $customer->wallet->creditcard->card_number
    It is possible to do quite similarly:
    Code:
    Customer customer = new Customer();
    customer.setWallet(new Wallet());
    customer.getWallet().setCreditCard(new CreditCard());
    customer.getWallet().getCreditCard().setCardNumber("1111-2222-3333-444");
    System.out.println(customer.getWallet().getCreditCard().getCardNumber());
    Ugly? Sure.

    The main reason I would be for __get and __set is that it creates less bloat in the classes itself and seems more semantic.

  24. #49
    SitePoint Addict
    Join Date
    Jan 2005
    Location
    Ireland
    Posts
    349
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by McGruff View Post
    I never use the verbose-ibility keywords public, private and protected (nor the fourth horseman of the anal retentive apocalypse, final). They don't actually do anything; they just sound like they do.
    They do something. They affect the members visibility depending on the current codes scope.

    Are you referring to the fact that it is possible to bypass this? Or maybe that there is no need to be so strict?

    At the end of the day, they clearly communicate to a user on how they are supposed to use your classes (and enforce).

    I might have a guess your response to the last paragraph could be "That's what the unit tests do".

  25. #50
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Underscores work OK for me as a simpler, more concise way to signify public/private. That is important - sure - but I don't believe it needs to be enforced in any way. It's like finding a sign in front of a hotel: "patrons may not enter their rooms by abseiling off the roof*". Well of course not. I'll use the front door.

    I think introspection could be a valid argument for verbose-ibility keywords (also type hints). Perhaps more and more tools which make use of reflection will emerge: things like dependency injection, refactoring apps.

    (*I confess I did actually do this once, but that's another story)


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
  •