RFC proposal for getters and setters

If you haven't been following the PHP development lately, then you have been missing out. Recently, there was a vote on the PHP mailing lists about adding short syntax for arrays (ala Javascript), yet the devs vote against it with childish excuses. And then there was this one guy who forked the PHP project and patched it with speed improvements and features the users have been wanting (which I completely agree with). You can also view the PHP RFC Wiki on the list of *possible* features and the ones that were denied. As you can see, there is much happening in the PHP community, but nothing to show for it (yet).

However, my post today will be on the RFC suggestion for built in getters/setters. To keep it blunt, I really dislike the C# approach... it's, just not very PHP. Just seems odd to have floating curly blocks with a "get" and "set" in it, with no real defined scope block. On top of that, the "property" keyword is way too complicated for what it is trying to achieve. The one thing I do agree with though, is the readonly modifier. My suggestion is loosely based on the Traceur Compiler by Google syntax (they use get/set keywords instead of function, within the class).

class FooBar {
	public $value;
	protected readonly $_readOnly;
	protected static readonly $_static;
	public get value() {
		return $this->value;
	}
	final public set value($value) {
		$this->value = $value;
	}
	public get readOnly() {
		return $this->_readOnly;
	}
	public static get static() {
		return self::$_static;
	}
	public function noop() {
		return;
	}
}

Admittedly, my suggestion is a bit more verbose than the C# variant, and pretty similar to regular getValue() and setValue() methods, but there are a few key differences.

Method Naming

Technically, are they still considered methods? Regardless, when you are writing getters and setters, you should use the words "get" or "set" in place of "function". This dictates to the class that these methods should be used anytime a property is being read or written to. On top of this functionality, the visibility modifiers are in effect (public, protected, private). This allows you to write to protected properties using a public setter, or reading from private properties with a protected getter (while in the class scope of course). Final and static keywords work exactly the same as well. Below is a quick example.

$foo = new FooBar();
$foo->value = 'setter'; // calls set::value()
$foo->readOnly = 'readonly'; // throws an error/exception
FooBar::$static = 'static'; // throws an error/exception
echo $foo->value; // calls get::value()
echo $foo->readOnly; // calls get::readOnly()
echo FooBar::$static; // calls get::static() statically

Getters and setters are not required, but when implemented, they are automatically triggered. If a property is public, without a getter/setter, then getting/setting a value works like it normally would. The major difference with this proposal is allowing the getting/setting of non-public properties, and never having to write getValue() or setValue() (you just modify the property directly like the example above).

Read Only

One of the features within the original proposal that I did like, was the readonly keyword. This keyword can be applied to any class property to set it into a read-only state, which basically disallows the use of a set method. It also disallows setting a value to the property directly, using the old functionality. But this sounds like the final keyword right? Technically yes, the major difference is that you can overwrite a readonly value in a sub-class, and not with a final.

Abstract and Interfaces

These could also be used with abstract classes and interfaces, like so.

interface FooBar {
	public get value();
	public set value();
}
abstract class FooBar {
	protected $value;
	abstract protected get value();
	abstract protected set value();
}

Now this is just a personal preference and style, and is something I have been thinking about lately (I have ideas for other RFCs as well), so don't expect this to actually happen! I also didn't get too in depth, for example, when are magic methods called during this process? I will leave those out unless for some odd reason this makes it in (heh). Let me know what you think!

Custom method for grabbing a row based on its ID

More times then none when working with a database, you need a general purpose method for grabbing fields from a row that matches an id. Cake has built in magic methods based on the table column that do just that, for example findById() or findBySlug(), but sometimes it grabs associated data that you do not want. Below is a basic method that you can place in your AppModel to grab a row based on its id, with optional parameters for restricting what fields to grab or what associations to contain.

/**
 * Grab a row and defined fields/containables
 *
 * @param int $id
 * @param array $fields
 * @param array $contain
 * @return array
 */
public function get($id, $fields = array(), $contain = false) {
	if (empty($fields)) {
		$fields = $this->alias .'.*';
	} else {
		foreach ($fields as $row => $field) {
			$fields[$row] = $this->alias .'.'. $field;
		}
	}
	return $this->find('first', array(
		'conditions' => array($this->alias .'.id' => $id),
		'fields' => $fields,
		'contain' => $contain
	));
}

With a little bit of editing, you can make it work for other fields other then id. You must also have containable listed in your behaviors for the 3rd argument to work. If you still aren't sure how to use this method, the following examples should help.

// Grab a basic row based on id
$user = $this->User->get($id);
// Grab a row and limit fields
$user = $this->User->get($id, array('id', 'username'));
// Grab a row, fields and associations
$user = $this->User->get($id, array('id', 'username'), array('Country', 'Profile'));