The Final Keyword

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

Post Reply
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

The Final Keyword

Post by Ollie Saunders »

As many of you will no doubt know I am writing a form management framework/package. Throughout writing it I've been watching of opportunities to use the 'final' keyword thinking that would some how improve my code. There have been opportunities where I have thought, yes final might work there but do I really want to impose that limitation? So far I have not used it at all, ever. I found plenty of use for abstract and I'm now quite an abstract fan but despite that final still doesn't seem to be doing it for me.

Does anybody use final and if so where?
and does it really improve things, what problem is it realistically addressing?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

I use it in few places, but important ones. They are used on four methods of my Object class. Why? Because I don't want anyone who is creating derivatives of this class to overwrite these functions. They, quite literally, make the class an Object. My Objects are controls of some fashion placed in the client be they visible or not.

Code: Select all

/**
	 * <summary>
	 * This magic method retrieves the data found in a property of the object.
	 * <param name="Name">The property name to retrieve.</param>
	 * <exception ref="DNAUnknownProperty">If no method nor property
	 * exists to set this variable, this exception will be thrown.</exception>
	 * </summary>
	 */
	final private function __get($aName)
	{
		if (method_exists($this, 'get' . $aName))
		{
			return call_user_func(array($this, 'get' . $aName));
		}
		elseif ($this->_propertyMap->exists($aName))
		{
			return $this->_propertyMap->$aName;
		}
		else
		{
			throw new DNAUnknownProperty();
		}
	}
	
	/**
	 * <summary>
	 * This magic method sets the data found in a property of the object.
	 * <param name="Name">The property name to set.</param>
	 * <param name="Value">The value to store in the property.</param>
	 * <exception ref="DNAUnknownProperty">If no method nor property
	 * exists to set this variable, this exception will be thrown.</exception>
	 * </summary>
	 */
	final private function __set($aName, $aValue)
	{
		if (method_exists($this, 'set' . $aName))
		{
			return call_user_func(array($this, 'set' . $aName), $aValue);
		}
		elseif ($this->_propertyMap->exists($aName))
		{
			return $this->_propertyMap->$aName = $aValue;
		}
		else
		{
			throw new DNAUnknownProperty();
		}
	}
	
	/**
	 * <summary>
	 * Add a property to the object.
	 * <param name="Name">The name of the property to add</param>
	 * <param name="Permissions">The permissions this property will be available
	 * to the object and associated objects. The default value is
	 * DNAPermissions::STANDARD_READONLY.</param>
	 * <remarks>Any other arguments passed to this function will be
	 * passed to the property during creation.</remarks>
	 * <returns>Boolean; Success or failure of the addition.</returns>
	 * </summary>
	 */
	final protected function addProperty($aName, $aPermissions = DNAPermissions::STANDARD_READONLY)
	{
		return call_user_func_array(array($this->_propertyMap, 'addProperty'), func_get_args());
	}
	
	/**
	 * <summary>
	 * Remove a property from the object.
	 * <param name="Name">The name of the property you wish to remove.</param>
	 * <remarks>This should only be called during destruction of the
	 * object.</remarks>
	 * <returns>Boolean; Success or failure of the removal.</returns>
	 * </summary>
	 */
	final protected function removeProperty($aName)
	{
		return call_user_func(array($this->_propertyMap, 'removeProperty'), $aName);
	}
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

Why? Because I don't want anyone who is creating derivatives of this class to overwrite these functions. They, quite literally, make the class an Object.
ahhh
* ole goes and adds final to loads of methods *

You ever made a class final?
User avatar
sweatje
Forum Contributor
Posts: 277
Joined: Wed Jun 29, 2005 10:04 pm
Location: Iowa, USA

Re: The Final Keyword

Post by sweatje »

ole wrote: Does anybody use final and if so where?
and does it really improve things, what problem is it realistically addressing?
I don't use final and I don't use private. I don't need any protection from my children.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

I've never used final before.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

It's rare that I wouldn't allow overwriting/overloading of a method, so it's even more rare that I'll want to declare a class as final. At this point, I do not see it happening any time soon.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: The Final Keyword

Post by Christopher »

ole wrote:Throughout writing it I've been watching of opportunities to use the 'final' keyword thinking that would some how improve my code.
Watching? I use plain old objects, the plain old way until something forces me to do otherwise -- which is rare. I haven't gotten very close to any need for final or private, but never say never. The interesting thing about keywords like final and private is that they have nothing to do with design and are ultimately only design limiters. I find the most interesting design ideas are the ones where I never imagined I would need to do that.
(#10850)
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

The interesting thing about keywords like final and private is that they have nothing to do with design and are ultimately only design limiters.
They help to make your design more robust and identity where things can be extended and where they cannot.
I find the most interesting design ideas are the ones where I never imagined I would need to do
Do you have any examples you could share?
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:They help to make your design more robust and identity where things can be extended and where they cannot.
I agree that they do those things, but those things are design limiters none the less.
ole wrote:Do you have any examples you could share?
- Composition over inheritance
- Front Controller
- MVC
- Doman Model
- Dependency Injection
- Test driven design
- Tell, don't ask
- ...............
(#10850)
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

I agree that they do those things, but those things are design limiters none the less.
Yes, absolutely.
- Composition over inheritance
- Front Controller
- MVC.....
and what do these unexpected design ideas have to do with design limitors such as final?
wei
Forum Contributor
Posts: 140
Joined: Wed Jul 12, 2006 12:18 am

Post by wei »

private variables are important if you want to enforce an API and keeping the API safe from internal changes such that backward compatiability is maintained. If a child class wish to interrogate the private data, a protected accessor may be considered with care.

Of course, some will argue that enforcing a public API may not be feasible in an agile enviornment. An API set in stone needs to be considered and designed with great care. The final keyword is used very very rarely.
bg
Forum Contributor
Posts: 157
Joined: Fri Sep 12, 2003 11:01 am

Post by bg »

wei wrote:private variables are important if you want to enforce an API and keeping the API safe from internal changes such that backward compatiability is maintained. If a child class wish to interrogate the private data, a protected accessor may be considered with care.
That's exactly it. Properly scoping your variables is a huge part of OOP.
bg
Forum Contributor
Posts: 157
Joined: Fri Sep 12, 2003 11:01 am

Post by bg »

Code: Select all

/* Prevent cloning of the instance */
	private final function __clone(){}
Should be in all your singleton classes
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

That doesn't prevent it. That just provides no additional clone behaviour and it has to be public anyway
This prevents it:

Code: Select all

final public function __clone() {
    throw new Exception('Cloning prohibited');
}
Good point though.
bg
Forum Contributor
Posts: 157
Joined: Fri Sep 12, 2003 11:01 am

Post by bg »

ole wrote:That doesn't prevent it. That just provides no additional clone behaviour and it has to be public anyway
This prevents it:

Code: Select all

final public function __clone() {
    throw new Exception('Cloning prohibited');
}
Good point though.
Well it does in fact prevent it, since it is a final private function. This means that even extending classes cannot call the __clone function. PHP will throw an error of it's own if you try. The __clone function does not need to be public.
Post Reply