sets and gets?

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Dave2000
Forum Contributor
Posts: 126
Joined: Wed Jun 21, 2006 1:48 pm

sets and gets?

Post by Dave2000 »

Sorry if this question is in the wrong place...

When should I use $object->variable and when should I use $object->get_variable() ? I often read that you should have a set and get function for every variable - and that you should not use $object->variable to reference a variable. However, when I look at various classes, there seems like a 99.98% chance there will be used in some places $object->variable to get values.

I am designing a database class. One of the functions is

Code: Select all

public function connect()
{
	$this->connection = mysql_connect($this->db_host, $this->db_username, $this->db_password);
	return;
}
Should this be written

Code: Select all

public function connect()
{
	$connection = mysql_connect($this->get_db_host(), $this->get_db_username(), $this->get_db_password());
        $this->set_connection($connection);
	return;
}
I am only asking because I see many people not using sets and gets all the time (for example pros on these forums).

Why should sets and gets be used in the first place? And, should I use them *all* the time?

Thanks

Shears :)
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Post by superdezign »

The whole purpose of get and set functions are so that OTHER objects have limited access to another object's properties. Using get and set functions in the class that they exist in is a waste of memory.
Dave2000
Forum Contributor
Posts: 126
Joined: Wed Jun 21, 2006 1:48 pm

Post by Dave2000 »

Couldn't that be controlled by setting properties as public, private, protected?
thinsoldier
Forum Contributor
Posts: 367
Joined: Fri Jul 20, 2007 11:29 am
Contact:

Post by thinsoldier »

If there is a special reason why a variable should _not_ be accessed via $obj->var then that var should be set to 'private' and a get/set created for it.

If there is no reason, there's nothing wrong with using $obj->var

The whole point of using getters/setters is so that you can trigger other things to happen whenever the var is accessed or updated and to verify the validity of the value it's being changed to: $obj->set_recordID('not a number') should return false and stop everything in its tracks if you only want numbers to be valid as a value of recordID
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

I always use getters and setters.

Yeah, its a giant pain to write them all. But then its a bigger pain when you realize a year down the road that you need to force a property to be of a certain type to fix a bug, or you want something to happen when a value is set, so then you have to search through every file that uses your model and change $object->var = 'something' to $object->setVar('something').

After doing that a few times I started forcing myself to use getters/setters.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

The question you raise Shears is a good one. There isn't a definitive answer. It all depends on how much encapsulation you want.

No encapsulation, widely accepted to be a bad thing 99% of the time:

Code: Select all

class Foo
{
    public $a;
}
Light encapsulation:

Code: Select all

class Foo
{
    protected $_a;
    public function getA()
    {
        return $this->_a;
    }
    public function setA($newA)
    {
        $this->_a = $newA;
    }
}
Although this is light encapsulation this gives you complete protection from the outside via the interface. For instance you can add a type hint or throw an exception in setA() to control what goes in. At the same time you still have the flexibility to use the property for anything you please inside the class and using the property directly is faster, easier to read and less typing. Most of the time this is what you want.

The next level of encapsulation up is the same as above only with $_a is set as private. Lots of people miss this level of encapsulation out as the difference is often small and the implication of inheritance is an "is a" relationship. The theory is if Foo is Foo then something that extends Foo is going to be Foo. Why should there be any difference with how we treat the data access in Foo with something else that is also Foo? I can appreciate this point of view but the implication of it is that will never use public nor private and so every property you ever declare is going to be protected... and formation of a habit begins. No longer are you going to consider what strength of visibility you need, you're just going to go with protected. Now this might sound great at first, less thought required, Pythonists might agree with you but on the other side of the hedge in the Ruby camp we're going to disagree. We think it's worth evaluating which is best even if it takes a little longer and consistency isn't the be all and end all of programming.

So it's worth thinking now. What really is the point in private? It does have a purpose and it is particularly useful in flex points. If you are writing a good library you will no doubt provide many flex points. Places where code can be extended, in order to change or augment it's purpose. Privates are really useful here. You want to prevent extenders from abusing the library and privates can be used to control this. Personally I have developed an anti-habit habit. I declare all my properties as private and change them to protected if I find it necessary later. I find that only roughly 50% of the time is it necessary to do so. Additionally (and this is good practise for interface level encapsulation also) the second a subclass needs access to it. First I ask myself - "Is the task I need to perform with this private in this subclass really the responsibility of the subclass? Should the super provide a method for doing it instead?" if the answer to the latter is yes then I can provide that method, for the benefit of the subclass, and retain my encapsulation.

Other ways you can improve your encapsulation:
  • Use a parametrized constructor to make it possible to only assign a value once.
  • If you have many properties not being used by several of your methods you may be able to put those properties and the methods that are using them into a second class. This is called the extract class refactor and will provide you with an additional level of encapsulation and also makes it possible to change the two sets of functionality separately. Unfortunately it also incurs the considerations of how those objects will interact and how they will be introduced to each (how instantiation will be managed). So it's a trade-off. Generally I only do it if I know I'm going to benefit from the increased polymorphism as well.
The next question you may be asking yourself is "How do I know how much encapsulation I need?". That's another post and another night, for it is late here.
Last edited by Ollie Saunders on Wed Jul 25, 2007 4:46 am, edited 1 time in total.
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post by stereofrog »

Wow, great post, ole! Respect.

If you don't mind a couple of comments:
ole wrote:The theory is if Foo is Foo then something that extends Foo is going to be Foo. Why should there be any difference with how we treat the data access in Foo with something else that is also Foo? I can appreciate this point of view but the implication of it is that will never use pubic nor private...
How using public would violate LSP?
Pythonists might agree with you but on the other side of the hedge in the Ruby camp we're going to disagree.
IIRC, in ruby all object fields are protected by default, moreover, it's just not possible to create a public or private one.

You want to prevent extenders from abusing the library and privates can be used to control this.
This is where I disagree. It's simply not your responsibility as library author to decide where your code can be extended and where not. Essentially, everytime you're using private you're making a design decision for someone else. Athough this "I know better what you need" attitude is common in the php world (compare with numerous language issues) I wouldn't call it good practice.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

How using public would violate LSP?
It doesn't. But we don't use public properties anyway.
IIRC, in ruby all object fields are protected by default, moreover, it's just not possible to create a public or private one.
OK my Ruby knowledge is still quite limited. I think you can do this:

Code: Select all

class Foo
    attr-accessor :a # Creates @a, a= and a. You could write them manually anyway
    private
    def somePrivateMethod
    
    end
end
Presumably if you can make a method private you can make an attribute private as well but I couldn't see how. Anyway the point I was making is that Ruby provides lots of ways of doing the same thing, Rubists don't believe in "the one true way", it's too limiting. I only recently obtained a decent book on the subject and the start of it is all philosophical you see. I find the idea pretty interesting and it is, very possibly, an extension of my own ideals. How it works in reality is something I've yet to experience.
This is where I disagree. It's simply not your responsibility as library author to decide where your code can be extended and where not.
Well a library isn't extensible from every point so you have to make judgement calls all the time. The more extensible it is the more complex the code is going to be and you don't want to do that unless there's a reason.
tdnxxx444
Forum Newbie
Posts: 23
Joined: Wed Mar 08, 2006 5:57 pm

Post by tdnxxx444 »

You should use accessors inside your classes as it reduces the coupling inside your classes. Only case where I think you shouldn't is if performance is a big issue.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

tdnxxx444 wrote:You should use accessors inside your classes as it reduces the coupling inside your classes. Only case where I think you shouldn't is if performance is a big issue.
How exactly can you have coupling inside a single class?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

ole wrote:How exactly can you have coupling inside a single class?
Well ... of course you can have coupling between any two pieces of code ... but it is not usually used at this level.

Look, this conversation about about getters and setters is really the same conversation about when to encapsulate code in a function -- but about a specific topic within that conversation. Take the following code:

Code: Select all

$a = $b + $c;

// OR

function add($b, $c) {
     return $b + $c;
}
$a = add($b, $c);
Most programmers would say that creating a function to add two numbers does not provide the benefits of encapsulating code in a function in this instance because it is below a certain level of complexity. The same reasoning should be applied to getters and setters. Is there a benefit to encapsulating the assignment of an object property within a method? If there is, due to some level of complexity, then implement getters/setters. If not, don't.
(#10850)
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

How exactly can you have coupling inside a single class?
It's a valid point - just not explained obviously. Think of it like this. It's not just one isolated class, it's a one class containing many members. Some members might require special handling (e.g. if they do not exist you might want to throw an exception). Coupling numerous class methods (and let's not forget subclasses) to the actual member means that when you want to add that Exception check, you need to go edit out all the direct member access, and replace them with a getter call.

Depending on how damaging internal coupling can be (and it's very hard to know in advance) I may use getters internally even though there's a performance cost to the constant getter calling. It's one situation where premature optimisation might be a concern. Notably though, it is possible in PHP5 to evade some of this maintenance cost by using __get()/__set() retrospectively if you need to switch public properties to being private, all without altering the established public API.

I actually used getters internally for example, in my OpenID library since it made a lot of sense at the time as classes are more tightly coupled than usual since OpenID is a specification (so it has limited flexibility when implementing) and it cut out a lot of annoying editing across all classes when properties needed access checks performed.

Cool earlier response, Ole. You're going to give me a run for my money in the awards next year ;).
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

trackback:
stereofrog wrote:in ruby all object fields are protected by default
Nope private :D just read it.


and back to now...
aborint wrote:If there is, due to some level of complexity, then implement getters/setters. If not, don't.
I like that. Neatly encapsulates the problem.. excuse the pun.
Depending on how damaging internal coupling can be (and it's very hard to know in advance) I may use getters internally even though there's a performance cost to the constant getter calling.
I really don't see how internal coupling exists. My methods don't change at runtime unlike the capabilities of objects, they don't interact outside of my control. If I change something in one method it's a given more that more than methods than itself may be affected but this isn't a problem because we ensure our classes don't get too large. Using getters and setters internally will provide some protection from this, I do use them now and then when I expect something to change, but really not very much and for the added complexity I don't see an "on by default" or blanket approach being worth it. The only time it might be an issue is if a different user is extending the class in a different file and is going to be less aware of what the superclass(es) are doing, especially if there are several layers of inheritance, but we have final and private to prevent those issues.
Maugrim_The_Reaper wrote:Cool earlier response, Ole. You're going to give me a run for my money in the awards next year
stereofrog wrote:Wow, great post, ole! Respect.
Thanks, guys. I think I had an inspired moment. Glory of one in the morning. :) OT: Here's a guy raving about a four in the morning.
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Re: sets and gets?

Post by McGruff »

Shears wrote:When should I use $object->variable
Never.
Shears wrote: and when should I use $object->get_variable()?
Always.

A class should always have a clearly defined interface otherwise no-one knows what you're supposed to do with it. Also tests so you know what happens when you pull on lever X. If you are testing, you can't set expectations if you don't have an interface to mock.

Incidentally this has nothing to do with protected, private or public. Save yourself an RSI and ignore them. Clutter just makes code harder to read and underscores work perfectly well as a way to mark out public/private. The one (rare) exception might be code which needs to know something about itself. Reflection was a nice tool to get with v5 but generally I look at ppp and "final" as the four horseman of the anal retentive apocalypse.
Should this be written...
First, I'd use mysqli - but what php version are you using?

Objects are meant to encapsulate some sort of behaviour and data. A Connection object should always encapsulate a unique connection. If it doesn't connection state - used database, current error etc - could be affected by different connection objects and nothing is actually being encapsulated.

So, I'd connect at instantiation and, if you're using mysql functions, be sure to also use the optional new link parameter. Set to true so that each instance always encapsulates a unique connection.

Code: Select all

function __construct($host, $user, $pass) {
    $this->connection = mysql_connect(
        $host, 
        $user, 
        $pass, 
        true);
}
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

A class should always have a clearly defined interface otherwise no-one knows what you're supposed to do with it.
You do realise we are talking about whether one should use getters and setters internally. The interface is on the outside.
Post Reply