Getters/setters in interfaces

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

User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Getters/setters in interfaces

Post by Chris Corbyn »

In the interest of keeping interfaces as simple as possible, do you guys think it's a bit silly to put getXXX() methods in an interface to accompany any setXXX() methods? Grr... that's worded terribly.. Effectively I have a bunch of classes whereby internally all I really care about is a toString() method giving me a valid string:

Code: Select all

interface Header {
  setName($name);
  setEncoder(Encoder $encoder);
  setMaxLength($length);
  setCharset($charset);
  setValue($value);
  toString();
}
The temptation is to throw in setters for all of those getters since the majority of end-users will likely want those setters to exist in any concrete classes, but regardless of whether the concrete class decides to implement getters or not it will still work internally. Do you think it's missing something without get() methods?

EDIT | I realise this seems like a bit a pointless question but I seem to be accumulating a lot of interfaces which comprise almost entirely of pairs of getters and setters.... and it's feeling a bit clunky.

EDIT 2 | The more I sit and think, the more I care less about the setXX() methods and trim this interface down to nothing more than a toString() method.
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Re: Getters/setters in interfaces

Post by Kieran Huggins »

I'd be inclined to drop the getters and setters entirely in favour of a simpler interface, courtesy of __call() and __toString():

You can still store the object by assignment, and you can "get" a property by passing no argument:

Code: Select all

$h = Header::name('name')->maxLen('50')->charset('utf-8')->value('bobs_your_uncle');
echo $h->charset();  // outputs: "utf-8"
$h->charset('latin-1'); // resets the charset
echo $h; // could print out the generated headers, courtesy of __toSring()
or, In one easy step:

Code: Select all

echo Header::name('name')->maxLen('50')->charset('utf-8')->value('bobs_your_uncle');
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Getters/setters in interfaces

Post by Chris Corbyn »

A fluid interface is something I was probably going to allow in the concrete classes, although not using any magic methods since it becomes incredibly difficult to document. It's actually just occurred to me that some other classes (i.e. the Message class) need to be able to get useful values from the headers for things like getting/setting recipient addresses and dates.

Hmmm.... I've come so far with this (with the "clunky" interfaces that provide what's needed) but starting to get cold feet. Might be time to just take a couple of days to mull over other possibilities, slap myself in the face and get back into it :P

On my 3rd beer tonight and it's a school night... naughty! Anyone gonna join me while I crack this one open? :)

Image
dml
Forum Contributor
Posts: 133
Joined: Sat Jan 26, 2008 2:20 pm

Re: Getters/setters in interfaces

Post by dml »

Chris Corbyn wrote:I
... I seem to be accumulating a lot of interfaces which comprise almost entirely of pairs of getters and setters.... and it's feeling a bit clunky.
I might be misunderstanding the nature of PHP interfaces, I only know the way they're used in Java, but if the only code that's likely to call a setter is the code that instantiated the object, then surely there's no point in having setters in the interface? I'm not a huge fan of setters even in concrete objects - I like things along the lines of $x = new ConcreteHeader("foo", "bar", "utf8"), so that $x is fully ready for business, and it's not going to break because I've forgotten to set an essential property.

Another way of looking at it: accessor methods and business methods are syntactically the same, but they have entirely different functions in an OO system. Accessor methods are used during initialisation for tuning internal properties of objects and wiring objects together. Once the object is plugged in and ready for business, it starts sending and receiving messages across the wires from other objects, and what an interface defines is the format of those inter-object messages.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Getters/setters in interfaces

Post by Chris Corbyn »

~dml, I agree. Moreso because (already implemented this too) something like a DateHeader takes a UNIX timestamp as a value, whereas a Subject header takes a string as a value, and an AddressHeader takes an array of addresses as a value. All business logic outside of the general behaviour a Header.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Getters/setters in interfaces

Post by Christopher »

I guess the part I am missing in your question is why you are implementing all those setters in the first place. I don't think I like or dislike setters or getters -- their intent is to control access to properties. When you need that they are a good choice, if you don't need that then they are extraneous. And, not every object is completely configured upon instantiation (thank goodness). I think you should use them as appropriate.
(#10850)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Getters/setters in interfaces

Post by Chris Corbyn »

The reason the setters were there was to make it easier to write a single factory class for various types of header. I was thinking more about this on the way to work and I've come to the conclusion that at the end of the day, trying to decouple a factory from the concrete classes it returns instances of is rather pointless overhead. As such I'm sticking with getName() and toString(). The reason getName() is in their is because it provides an identifier for storage and lookup purposes. All the other stuff is not needed in the interface.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Getters/setters in interfaces

Post by Jenk »

The getters and setters are just as valid part of an interface as any method name. I don't get why there is a "taboo" about getters/setters, because there most certainly is no significant reason to be wary of them. You should be more wary about public properties, as there is no control over the value(s).
User avatar
dreamscape
Forum Commoner
Posts: 87
Joined: Wed Jun 08, 2005 10:06 am
Contact:

Re: Getters/setters in interfaces

Post by dreamscape »

I think Fowler has a decent essay/article on the topic, but I can't seem to locate the URL at the moment.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Getters/setters in interfaces

Post by Chris Corbyn »

Jenk wrote:The getters and setters are just as valid part of an interface as any method name. I don't get why there is a "taboo" about getters/setters, because there most certainly is no significant reason to be wary of them. You should be more wary about public properties, as there is no control over the value(s).
I wasn't wary about the use of them. I was only wary about the size of my interface. Interfaces should (as much as possible) be very short and concise. As it turns out, I dropped them entirely... the system doesn't care about them. If someone wanted code a concrete header which always returns a static string then so be it :)

~ dreamscape, thanks, I'll have a poke around on his site. I was just reading an old article on there yesterday actually, surrounding mocks (and his seemingly (justified) opposed views to them).

Code: Select all

<?php
 
/*
 Header Interface in Swift Mailer.
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 
 
/**
 * A MIME Header.
 * @package Swift
 * @subpackage Mime
 * @author Chris Corbyn
 */
interface Swift_Mime_Header
{
  
  /**
   * Get the name of this header (e.g. Subject).
   * The name is an identifier and as such is immutable.
   * @return string
   */
  public function getFieldName();
  
  /**
   * Get the field body, in it's syntactically valid RFC 2822 form.
   * @return string
   */
  public function getFieldBody();
  
  /**
   * Get this Header rendered as a compliant string.
   * @return string
   */
  public function toString();
  
}
 
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Getters/setters in interfaces

Post by Christopher »

Chris Corbyn wrote:... I was only wary about the size of my interface. Interfaces should (as much as possible) be very short and concise. As it turns out, I dropped them entirely... the system doesn't care about them.
To comment on this point, creating "short and concise interfaces" is a guideline -- but it is not a goal unto itself. If an interface needs to be large and complex, then it can be large and complex. The important thing is that you are aware of the potential pitfalls so you can make wise design decisions when changes are required. What is currently not a tipping point in a design decision may change as circumstances change.
(#10850)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Getters/setters in interfaces

Post by Chris Corbyn »

arborint wrote:creating "short and concise interfaces" is a guideline -- but it is not a goal unto itself. If an interface needs to be large and complex, then it can be large and complex.
Indeed :) But if your interface has things in it which (although nice and descriptive) are not requirements then you probably don't want them in your interface. Once you start mocking interfaces for testing, a shorter interface is far easier to deal with than a complex one. There was a nice article on JavaRanch (I'll look for it in a tick) about dependency injection, and it gave a nice example of how a complex interface becomes a pain to implement (using the not very complex HashMap as an example). Not that HashMap contains unwanted fluff, but if you don't need all those methods then trimming them out of the interface can only be a good thing. Increase flexibility, simplify your API, make testing easier...

EDIT | http://www.javaranch.com/journal/200709 ... sting.html
EDIT 2 | Hmm... maybe that's not the article I was thinking of :crazy:
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Getters/setters in interfaces

Post by Jenk »

Let's also not forget that if an Interface is overly descriptive, you may as well not bother having an interface at all, and just use the classes interface as the er.. interface.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Getters/setters in interfaces

Post by Chris Corbyn »

Jenk wrote:Let's also not forget that if an Interface is overly descriptive, you may as well not bother having an interface at all, and just use the classes interface as the er.. interface.
Except then you've tightly coupled your dependant class to a concrete class which will need to follow that code around everywhere == bulky.
dml
Forum Contributor
Posts: 133
Joined: Sat Jan 26, 2008 2:20 pm

Re: Getters/setters in interfaces

Post by dml »

Jenk wrote:The getters and setters are just as valid part of an interface as any method name. I don't get why there is a "taboo" about getters/setters, because there most certainly is no significant reason to be wary of them.
I wouldn't go so far as to say taboo, but there are reasons to ask questions.

Code: Select all

 
// In many circumstances, access to internal properties of an object
$x = $foo->getX(); 
doSomethingWithX($x);
 
// is better off encapsulated like this:
$foo->doSomethingWithX();
 
If it's an access to a related object, for example:

Code: Select all

 
$school = $teacher->getSchool();
$address = $school->getAddress();
 
the issue is that the users of the Teacher object aren't just using its surface interface, they're reaching beyond it and making assumptions about the other object relationships in the system. This can come to light with mock object testing, which tends to focus programmer attention on defining an object in terms of its relationships with immediate neighbors. It's just a fruitful line of thought to follow, it's a matter of experience and judgment to know when rigorous thinking is turning into religion.
Post Reply