Page 1 of 2
Use of static methods within an object?
Posted: Thu Nov 09, 2006 3:31 am
by Jenk
Stumbled upon the thought of using a static method in place of an object method, for functions that do not require access to object properties; and example:
Code: Select all
class Locator
{
private static function _formatName($name)
{
$name = ucwords(str_replace('_', ' ', $name));
return str_replace(' ', '/', $name);
}
public function loadClass($name)
{
$name = self::_formatName($name); // instead of $this->_formatName()
if (!is_file($name) || !is_readable($name))
{
throw new Locator_Exception(
'class file "' . $name . '" does not exist, or cannot be read'
);
}
else
{
include_once $name;
}
}
}
?>
The theory being that the object is not 'weighed down' with methods that do not need access to the objects live properties, if you understand what I mean..
In the above example, it propbably makes negligible difference, but I'm sure there will be circumstances where it could make a lot of difference.
What do you guys think of this practice?
Posted: Thu Nov 09, 2006 4:11 am
by theYinYeti
I tend to agree, although there may be exceptions.
Posted: Thu Nov 09, 2006 4:38 am
by Chris Corbyn
You're really going to see minimal overhead differences for doing this. I do it on occassion but be careful not to scatter this around too much because unravelling it all again when you need something a bit more stateful is going to be a pain. If you're calling a method as part of the object then the fact it calls another method in the *already instantiated* object is not really any different to what you're doing with a static.
Posted: Thu Nov 09, 2006 4:39 am
by johno
If there is a method that don't needs to know about object properties its a bad smell. But it could be just a simple helper method like in this case. I would just make it a private (nonstatic) method and factor that out if some duplication in different classes arises. I have no idea why it would be better to make it static. Can you?
Static keyword is IMHO a sign that something is not in right place.
Posted: Thu Nov 09, 2006 4:43 am
by Chris Corbyn
johno wrote:If there is a method that don't needs to know about object properties its a bad smell.
That's entirely subjective. I commonly place a static factory method in one of my central classes in a system to make retreiving other objects easier. It's not bothered what the rest of the class does but I certainly wouldn't call it a smell. Unless of course that's the sort of thing you meant by a helper.
Posted: Thu Nov 09, 2006 5:09 am
by theFool
Is there a sense in a private static method?
Posted: Thu Nov 09, 2006 5:16 am
by johno
d11wtq wrote:That's entirely subjective. I commonly place a static factory method in one of my central classes in a system to make retreiving other objects easier. It's not bothered what the rest of the class does but I certainly wouldn't call it a smell. Unless of course that's the sort of thing you meant by a helper.
You are right. Duplication is the main smell, but duplication always starts when things aren't in their right place. So this is something I recognize as a pre-smell. If there is something static it can be always refactored out. You may not need that refactor that out immediately or even ever. But as soon there starts duplication you will realize that mostly these helpers need to be refactored into separate classes.
Suppose I want to make different naming convention for classes and paths? Whats going to be refactored out? Right - formatName into separate NamingConvention class.
Static factory method is IMHO a helper.
Posted: Thu Nov 09, 2006 6:17 am
by Jenk
theFool wrote:Is there a sense in a private static method?
Yes, in that example, it's only available to the Loader class and it's objects. Just where I want it to be. It wouldn't be any different if it were not a static method, it would still be private, as it is not a part of the interface.
Posted: Thu Nov 09, 2006 6:42 am
by sike
i tend to avoid statics whenever possible. for me they are "objectified" globals - and that smells alot (at least for my nose (: ).
additionally they are harder to test.
cheers
Chris
Posted: Thu Nov 09, 2006 7:47 am
by Maugrim_The_Reaper
Static methods aren't necessarily bad. The problem is that their global nature makes them prime candidates for overuse. A good idea is to look at how a static will be used. If its a general helper function of limited use in a narrow scope, then it's probably okay. If it's a very useful function in a wide scope then its getting decidedly smelly. Once a static proliferates through a codebase it becomes difficult to maintain loosely coupled classes - the static becomes a dependency in too many places. Multiply the number of similar statics by a few factors and you have a potential bombsite on your hands

.
A recent example is the Zend Framework - there's a lot of backpeddling over the Zend class which offered Zend::loadClass(), Zend::dump(), and other general use statics. Since they are very useful across the whole framework, and even into the code based on the framework, it proliferated quickly. The result is a trend to refactor the statics into separate classes. For example, in the 0.20 incubator you now have Zend_Registry which should replace Zend::register() and Zend::registry(). The statics in incubator are now simple proxies using Zend_Registry for backwards compatibility (something I disagree with since the statics still exist, but won't blame folk for since it would spark a BC rebellion in the ranks of users).
My rule of thumb is to avoid statics unless they clearly add an advantage. If no apparent advantage is evident, then there's no real reason to use a static.
Posted: Thu Nov 09, 2006 7:58 am
by theFool
Jenk wrote: It wouldn't be any different if it were not a static method, it would still be private...
Exactly, so we have both the same thoughts but different conclusions.

Personally, I only would make a method static if there is a concrete reason for that. In your example, I would let that method be non-static, just because it can only be accessed by objects of that class anyway.
Posted: Thu Nov 09, 2006 8:20 am
by Jenk
The purpose really is duplication, but not in a number of lines form.. in memory form.
This can be labelled premptive optimisation, but the theory is: every object has a copy of the method, vs every object references only one instance of the method.
The reason for it being private is negligible. It's private because I don't want anything outside of that class using it, if I change it to public in my original post, it bears no difference on the topic.

Posted: Thu Nov 09, 2006 12:41 pm
by alex.barylski
If I remember correctly using a static method will not reduce the overhead of a function call as the 'this' pointer is the only additional overhead (de-referencing this pointer).
Static are not only used for performance, but for reason...
In some OOP languages such as C++ you can declare a method as 'const' which prevents that method from manipulating the object, but still allows retreival of data members.
Static methods are similar in nature except that they should be used when the method should never be used to manipulate or access the class (object) which it belongs to.
Sometimes a function logically belongs to a class but doesn't act specifically on that classes data, in which case a static is typically used.
For instance in MFC there is a CFile class:
http://msdn.microsoft.com/library/defau ... embers.asp
Most of the operations deal with object manipulation, but at the bottom there are some statics, mostly out of nesseccity...
They use statics in this case because...the delete() or rename() operations are very much a part of a file "class" but do not require an "object" therefore they remain as static both for performance and for function.
My point is statics are fine, like any technique as long as your can actually justify their use and the positives outweigh the negatives - giver!!! Whether they should be used as a performance boost...not unless they make sense to do so, but if they do...yes of course captialize on the performance gains (albeit as minimal as they are).
Cheers

Posted: Thu Nov 09, 2006 2:38 pm
by Maugrim_The_Reaper
They use statics in this case because...the delete() or rename() operations are very much a part of a file "class" but do not require an "object" therefore they remain as static both for performance and for function.
The point I would make (in PHP at least) is that using statics for performance gains is premature optimisation. In the scope of Design, all that achieves is numerous global methods and little measurable performance gain (has anyone using this actually measured the gain???). There are times to compromise between good design and optimisation but I doubt statics is one of them. I'd accept a tiny performance hit for looser coupling - most of us have accepted such hits in the past when PHP5 first came out

.
In MFC those concerns are moot - MFC is a class library and most libraries are tightly coupled. If you look at PHP, the Zend Framework is the opposite - it's extremely loosely coupled and allowing too many statics only damages that aspect.
Note that using a static in a class, means that class must be aware of the static's class name. If we spend so much time discussing alternatives to direct instantiation and Singleton static calls like Class_Name::getInstance() peppering our class constructors (tight coupling) - like Registry, Service Locator and Factories, then we should apply the same measures where possible to another reason for class coupling - static methods.
Posted: Thu Nov 09, 2006 4:01 pm
by Chris Corbyn
Maugrim_The_Reaper wrote:has anyone using this actually measured the gain???
I've just done a few benchmarks and it's negligible at best. I wanted to measure the actual memory usage and time taken for just one call to the method but xdebug is whining about undefined functions on the server I have access to.
Speed comparisons calling the methods:
Code: Select all
<?php
class StaticGainsTest
{
private function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = $this->getNull();
}
return $ret;
}
}
$start = microtime(true);
$o = new StaticGainsTest();
$o->getLotsOfNull();
$end = microtime(true);
echo "Called non-static method 100000 times in ". ($end - $start) . " seconds\n";
?>
Code: Select all
Called non-static method 100000 times in 6.48325991631 seconds
Code: Select all
<?php
class StaticGainsTest
{
private static function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = self::getNull();
}
return $ret;
}
}
$start = microtime(true);
$o = new StaticGainsTest();
$o->getLotsOfNull();
$end = microtime(true);
echo "Called static method 100000 times in ". ($end - $start) . " seconds\n";
?>
Code: Select all
Called static method 100000 times in 6.25048303604 seconds
Speed comparisons creating the objects:
Code: Select all
<?php
class StaticGainsTest
{
private function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = $this->getNull();
}
return $ret;
}
}
$start = microtime(true);
$collection = array();
for ($i = 0; $i < 10000; $i++)
{
$collection[] = new StaticGainsTest();
}
$end = microtime(true);
echo "Created a collection of 10000 objects with a no static methods in " . ($end-$start) . " seconds\n";
?>
Code: Select all
Created a collection of 10000 objects with a no static methods in 0.0555810928345 seconds
Code: Select all
<?php
class StaticGainsTest
{
private static function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = self::getNull();
}
return $ret;
}
}
$start = microtime(true);
$collection = array();
for ($i = 0; $i < 10000; $i++)
{
$collection[] = new StaticGainsTest();
}
$end = microtime(true);
echo "Created a collection of 10000 objects with a static method in " . ($end-$start) . " seconds\n";
?>
Code: Select all
Created a collection of 10000 objects with a static method in 0.028272151947 seconds
Memory comparisons calling the methods:
Code: Select all
<?php
class StaticGainsTest
{
private function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = $this->getNull();
}
return $ret;
}
}
$o = new StaticGainsTest();
$o->getLotsOfNull();
echo "Ran non-static method 100000 times using " . (xdebug_peak_memory_usage()) . " bytes in memory\n";
?>
Code: Select all
Ran non-static method 100000 times using 6164328 bytes in memory
Code: Select all
<?php
class StaticGainsTest
{
private static function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = self::getNull();
}
return $ret;
}
}
$o = new StaticGainsTest();
$o->getLotsOfNull();
echo "Ran static method 100000 times using " . (xdebug_peak_memory_usage()) . " bytes in memory\n";
?>
Code: Select all
Ran static method 100000 times using 6164392 bytes in memory
Memory comparisons creating the objects:
Code: Select all
<?php
class StaticGainsTest
{
private function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = $this->getNull();
}
return $ret;
}
}
$collection = array();
for ($i = 0; $i < 10000; $i++)
{
$collection[] = new StaticGainsTest();
}
echo "Created a collection of 10000 objects with a no static methods using " . (xdebug_peak_memory_usage()) . " bytes in memory\n";
?>
Code: Select all
Created a collection of 10000 objects with a no static methods using 1994504 bytes in memory
Code: Select all
<?php
class StaticGainsTest
{
private static function getNull()
{
return null;
}
public function getLotsOfNull()
{
$ret = array();
for ($i = 0; $i < 100000; $i++)
{
$ret[] = self::getNull();
}
return $ret;
}
}
$collection = array();
for ($i = 0; $i < 10000; $i++)
{
$collection[] = new StaticGainsTest();
}
echo "Created a collection of 10000 objects with a static method using " . (xdebug_peak_memory_usage()) . " bytes in memory\n";
?>
Code: Select all
Created a collection of 10000 objects with a static method using 1994576 bytes in memory