Your question triggered some discussion here. Hopefully nobody minds me just 
pasting it here FYI. It's raw and a bit chaotic but hopefully you get some 
feeling what we were talking about.

Regards
Tomas Liubinas
 

[14:27:56 | Pakeitė 14:28:06] Tomas Liubinas: could anyone pls provide any 
arguments for Christopher regarding oxSuperCfg?
[14:31:14] Tomas Liubinas: I can't because mostly I tend to agree with him.
[14:31:50] [ox] Sarunas Valaskevicius: I basically agree also. but.. unit tests
[14:32:08] [ox] Sarunas Valaskevicius: it would be hard to make unit tests 
which use singleton directly
[14:33:28 | Pakeitė 14:34:02] [ox] Sarunas Valaskevicius: also - another 
approach would be to pass config as param to class constructors (or 
functions).. but then this may seem redundant and not very nice code, since 
oxConfig does change, also oxSession and other classes.. would be not nice code
[14:33:58] Tomas Liubinas: why it is hard to use in unittests?
[14:34:28] [ox] Sarunas Valaskevicius: e.g. 

func aa(){
 oxConfig::getInstance()->asasd();
}
[14:34:35] [ox] Sarunas Valaskevicius: you can not mock it
[14:34:42] [OXID] Jürgen Gramenz: private and static...thats evil
[14:34:47 | Pakeitė 14:35:31] [ox] Sarunas Valaskevicius: except using 
modConfig - which is also not really nice - some code for binding it (basically 
unit tests code) resides in getInstance
[14:35:58 | Pakeitė 14:36:27] [ox] Sarunas Valaskevicius: and 

func aa(){
 $this->getConfig()->asasd();
}

can be mocked normally
[14:36:16] [ox] Sarunas Valaskevicius: this is the only reason I guess it was 
implemented like this
[14:37:40 | Pakeitė 14:39:19] [ox] Sarunas Valaskevicius: private and static 
not always evil (these are intended language constructs) - but it is evil in 
eShop, yes :) (because of modules). (i.e. not overusing it, brings less complex 
API [private], while static is for static data :) )
[14:39:37] [OXID] Jürgen Gramenz: no, try to test a real singleton  (i mean not 
only getInstance )...f.i. if you would like to test privacy of __clone() you'll 
have to use reflection...the real heck is the static
[14:40:09] [OXID] Jürgen Gramenz: you cannot unset this... and this is a bit 
tricky if you would like to test different cases....
[14:40:50] [OXID] Jürgen Gramenz: i mean....i would be glad if someone could 
show me a real good unittesting of a singleton
[14:44:22] [ox] Sarunas Valaskevicius: btw - oxSuperCfg contains lots of static
[14:45:01 | Pakeitė 14:46:35] [ox] Sarunas Valaskevicius: it is composed of 
static variables only :)
[14:47:47 | Pakeitė 14:48:25] [ox] Sarunas Valaskevicius: so it is basically 
same getInstance, with a shortcut through this objects method - which is only 
really needed for unit tests (plus it caches instance twice - in oxConfig and 
in oxSuprtCfg)
[14:49:21] [ox] Sarunas Valaskevicius: " real good unittesting of a singleton " 
- test object initialization and caching of instance - getInstance does not do 
more
[14:49:54 | Pakeitė 14:49:59] [ox] Sarunas Valaskevicius: for other methods - 
you can create object new and mock it, it is not needed to use getinstance in 
unit tests
[14:50:53 | Pakeitė 14:52:23] Tomas Liubinas: imo it is no more dificult to 
test than any other class having static method. And it looks like we can not 
get away without using no static at all
[14:52:03] [ox] Sarunas Valaskevicius: yes - static is ok, if used for static 
data. 

another problem with singletons - they tend to be big. and yes - oxConfig is 
huge.. (maybe too huge)
[14:52:03] [OXID] Jürgen Gramenz: please tell us about your testing strategies 
for singeltons and/or static vars...i think it would be useful for efire people
[14:54:55] [ox] Sarunas Valaskevicius: like I said, 

func aa(){
 oxConfig::getInstance()->asasd();
}

is a problematic case, (described above), unless there would be setInstance :)
[14:55:15] Tomas Liubinas: this is how we mock it:
[14:55:38] Tomas Liubinas: oxConfig::getInstance():
[14:55:47] Tomas Liubinas:    
   /**
     * Returns singleton oxConfig object instance or create new if needed
     *
     * @return oxConfig
     */
    public static function getInstance()
    {

        if ( defined( 'OXID_PHP_UNIT' ) ) {
            if ( isset( modConfig::$unitMOD ) && is_object( modConfig::$unitMOD 
) ) {
                return modConfig::$unitMOD;
            }
        }

        if ( !self::$_instance instanceof oxConfig ) {
                //exceptions from here go directly to global exception handler
                //if no init is possible whole application has to die!
                self::$_instance = new oxConfig();
                self::$_instance->init();
        }
        return self::$_instance;
    }
[14:57:30] Tomas Liubinas: etc :)
[14:57:50] [OXID] Jürgen Gramenz: hmm, looks like phpunit driven design ;)
[14:57:55] [ox] Sarunas Valaskevicius: this is the case " which is also not 
really nice - some code for binding it (basically unit tests code) resides in 
getInstance"
[14:58:28] [OXID] Jürgen Gramenz: but interesting way
[14:58:41 | Pakeitė 14:58:53] [ox] Sarunas Valaskevicius: ghmm.. maybe it 
should be changed to setInstance($obj) method?
[14:59:06] [OXID] Jürgen Gramenz: dependency injection would be perfect
[14:59:10] [OXID] Jürgen Gramenz: but
[14:59:22] [OXID] Jürgen Gramenz: is it a singleton after this?
[14:59:53] [ox] Sarunas Valaskevicius: aha :) by making self::$_instance 
protected it is possible even without using setInstance of unit code in 
getinstance
[15:00:33 | Pakeitė 15:00:38] [ox] Sarunas Valaskevicius: class, extended in 
unit tests, can have setInstance, and set to protected oxConfig::$_instance
[15:00:43 | Pakeitė 15:01:08] [ox] Sarunas Valaskevicius: so shop code would be 
cleaner
[15:10:56 | Pakeitė 15:16:35] [ox] Sarunas Valaskevicius: ghmz.. passing 
through constructor con - memory usage increase (+ a bit of time to assign it 
locally) for every object created..
[15:20:00] Tomas Liubinas: I guess Erik will ask first of all why we using 
sigeltons at all :)
[15:20:22] Tomas Liubinas: So the reason: It is not possible to fit all classes 
under one hierarchy tree
[15:21:12] [ox] Erik Kort: @Tomas: yes .. I will ask .. but wait ..
[15:21:14 | Pakeitė 15:22:57] [ox] Erik Kort: BTW: Singleton is consider by 
some very knowledgable people to be more of an anti-pattern then as an design 
pattern .. I tend to agree with that .. You are putting 2 independent purposes 
in a class. A) its intended purpose and B) the global once instantiation. You 
are making basically a global variable again .. There are better ways for that. 

Answer to testing: dependency injection solves _alot_ of testing problems, and 
actually makes you classes more flexible at the same time .. 

BTW2: Static functions should also only be used in exceptional cases.. as it is 
procedural code again .. no real OO anymore  .. you basically just have an 
function namespace... if you use non-public static members to much to try to 
achieve the OO a bit again, you lose your slight performance advantage you had 
and your code gets to tightly coupled.. Meaning that it gets hard to refactor 
:) .. see some of the efire static classes .. .... 
its way over used in the PHP world because people think it is significantly 
faster. Its actuall a bit faster .. not that much .. But most of the time 
(>95%) of runtime is lost on other stuff .. (DB access, file access, network 
access and in general amount of code in total to run)

BTW3 .. In eFire we dont make any new Singleton classes anymore .. We still 
have legacy classes using them.. Same for static ... newer classes hardly get 
static functions anymore. .. Legacy classes who are primerally like function 
namespaces are still maintained in that design, but no newer....
[15:21:20] [ox] Dainius Bigelis: wow
[15:23:19] [ox] Erik Kort: BTW .. we should have discussed this in the 
DEV-GENERAL mailing list :D
[15:24:34] [ox] Sarunas Valaskevicius: we can paste it., as this way discussion 
is a lot faster
[15:24:42] [ox] Sarunas Valaskevicius: (no irc channel yet :) )
[15:28:58] [ox] Sarunas Valaskevicius: what about "passing through constructor 
con - memory usage increase (+ a bit of time to assign it locally) for every 
object created.." ? is it in 5% performance loss we should not care about ?
[15:29:09] [ox] Erik Kort: BTW .. I propose to _replace_ skype in the 
development with IRC ..  so we only have one tool for internal and external 
chats ... What do you think ? (Nettalk is a good Win client for that ..)
[15:30:13] [ox] Erik Kort: @Sarunas: yes dont care about it .. because its 5% 
OR LESS THAN 5% .. see the "(>95%) runtime"  part of text
[15:30:46] [ox] Erik Kort: when you you have perfomance problems you profile.. 
you will always find way bigger peerfomance losses then the static calls ..
[15:31:40] [ox] Sarunas Valaskevicius: most of the time these bigger calls do 
more functionality, and summing memory and time used for DI, could be quite 
much not to notice
[15:32:09 | Pakeitė 15:32:36] [ox] Erik Kort: and if you actuall have found 
one, its a case where recursivly millions of time a function is called ... That 
you can make static then .. But I have seen one yet :) .. And to screw up the 
OO design for that?, .. no thanks .
[15:33:53] [ox] Erik Kort: With good OO design comes good maintainability of 
code .. THATS is directly saved time and therefore $$$ for the company ..
[15:34:06] [ox] Sarunas Valaskevicius: true
[15:34:35] [ox] Erik Kort: Besides, I enjoy programming more if it is good OO 
code ;)
[15:36:58] Tomas Liubinas: this discussion is a good argumetn for irc
[15:38:57] Tomas Liubinas: well ok but here comes the practical side again.
[15:39:33] Tomas Liubinas: This non singelton approach coud work for java when 
you fit all the classes under one class hierarchy tree
[15:39:48] Tomas Liubinas: but we simply can't do that
[15:39:53] [ox] Erik Kort: so .. in the end .. we have the fact where we have 
singletons and statics in shop & efire ... But its functional working .. so we 
have to live with it ... But when we all keep this in mind, we can slowly , 
without taking actuallly extra time (tasks), refactor that together when we 
need to change that class for another reason .. When we need to refactor that 
class any way .. First thing for easy transition is decoupled design and code 
.. Dont underestimate this .... with decoupled design can gradually refactor 
... in eFire we now have rougly >1.000.000 of code and its partially not 
decoupled... Those are parts we cant really refactor gradually today ..
[15:40:05] Tomas Liubinas: one of the reasons 3rd party libs
[15:40:14] Tomas Liubinas: we need config eg in smarty plugins
[15:40:26 | Pakeitė 15:40:36] [ox] Erik Kort: @Tomas: why cant we do that ?  
and why do we need one class hierarchy if we want to prevent singletons ?
[15:40:54 | Pakeitė 15:41:24] [ox] Sarunas Valaskevicius: smarty plugins can 
get vars from view -> so it is not that big problem
[15:41:13] [ox] Sarunas Valaskevicius: i.e. it is possible
[15:41:38] [ox] Erik Kort: yes... its possible to not use singletons without a 
one class hierarchy ..
[15:41:57 | Pakeitė 15:42:09] Tomas Liubinas: unless all the libs comes in 
packages like com.smarty.compiler we can't inject the var deep down to every 
instantiated object
[15:42:02] [ox] Erik Kort: I want irc now ! :D
[15:43:22 | Pakeitė 15:43:50] [ox] Sarunas Valaskevicius: did not really 
understood Tomas..
for our smarty plugins we can use this.. are there other 3rd party libs where 
it is needed ?
[15:44:16] [ox] Sarunas Valaskevicius: ghmm.. maybe editor? would need to 
check..
[15:44:29] Tomas Liubinas: smarty plugin is called from template by (I guess) 
eval'ing some code, it's a simple function the only way to get config there is 
singelton (or any other static peace )
[15:44:39] Tomas Liubinas: the same is with almost any other 3rd party lib
[15:44:48] [ox] Sarunas Valaskevicius: no - it gets whole smarty with all its 
params
[15:44:50] [ox] Erik Kort: BTW We can use an global registry .. (I'm not sure 
what the design pattern name for this is)  ... Something like Zend_Registry 
will do ... You have same affects as singleton .. (as for global only once 
existence of an object) .. without making the class itself untestable or 
limited ..
[15:45:15] [ox] Sarunas Valaskevicius: e.g.
function smarty_function_oxgetseourl( $params, &$smarty )
{
[15:45:25] Tomas Liubinas: @Sarunas - I use smarty just for illustration, the 
same is with any other 3rd party lib
[15:45:44 | Pakeitė 15:47:50] Tomas Liubinas: Wordpress? Jumla? Drupal?
[15:45:49] [ox] Sarunas Valaskevicius: any other 3rd party lib which inludes 
oxid code ?
[15:45:59 | Pakeitė 15:46:19] [ox] Erik Kort: Just heard .. the design pattern 
ist called "Registry" .. :D thnx Jürgen ..
[15:47:00] [ox] Sarunas Valaskevicius: how registry is it different from 
globals ?
[15:47:00] Tomas Liubinas: @Sarunas, yes we can solve smarty case, but we do 
not want to limit ourselves to partuicular 3rd party libs
[15:48:43 | Pakeitė 15:50:09] [ox] Sarunas Valaskevicius: @Tomas: ok, so we 
dont have the problem now. thus - we should not solve it now (limit our actions 
by problem which is not here) .. or no ?
[15:48:45] Tomas Liubinas: Would anybody mind if I paste this conversation to 
dev-general?
[15:49:38] [ox] Danijel Matkovic: <-- votes for irc too (smirk)
[15:52:37 | Pakeitė 15:52:56] [ox] Erik Kort: BTW .. Whats the difference 
between an registry and a true global variable or singleton then, you might ask 
 ? ..

 welll, with a registry you have the global access buts its encapsulated / 
decoupled .. You have an interface to it. Depency injection does works here .. 
setup will inject a test object or mock/stub whatever you want in the registry 
right before testing the function ... and voila .. its testable ...
[15:57:52 | Pakeitė 16:00:13] [ox] Sarunas Valaskevicius: @Erik: ok, clear. but 
the same result is with singleton, whose value you can set in unit tests?
[15:58:28] [ox] Sarunas Valaskevicius: e.g. by making self::$_instance 
protected it is possible even without using setInstance of unit code in 
getinstance
class, extended in unit tests, can have setInstance, and set to protected 
oxConfig::$_instance
[16:07:52] [ox] Erik Kort: @Sarunas: Then you still have all of the OO design 
weaknesses of the singleton pattern itself .. 

To insert a dummy object in to the registry is a on liner .. derive a extra 
class to test is more .. and that is more coupled to class implementation 
itself ..
[16:08:14] [ox] Erik Kort: mom in telko .
[16:10:40] [ox] Sarunas Valaskevicius: derived extra class is not used more 
than just seting instance.. so it has only one one-liner function (setInstance) 
and is not used anywhere else. i.e. objects does not get to use this derived 
class.

about class coupling - yes, agree
[16:32:32] Tomas Liubinas: ok
[16:32:36] Tomas Liubinas: so lessons learned:
[16:32:47] Tomas Liubinas: - Dependency injection
[16:32:51] Tomas Liubinas: - Registry design pattern
[16:33:16] Tomas Liubinas: 
http://blog.astrumfutura.com/archives/340-The-Zend-Framework,-Dependency-Injection-and-Zend_Di.html
[16:40:58] [OXID] Jürgen Gramenz: wowow, dependency injection container ... a 
dream architecture....class instantiation via di container and putting it into 
the registry and then di via getting the intantiated object from the 
registry.... but thats a hell of a work to refactor... there is already an 
interesting di container: pimple http://github.com/fabpot/Pimple/tree/master 
... the only thing is...its for php 5.3...but the idea behind it and the class 
architecture is brilliant in my opinion
[16:41:34] [OXID] Jürgen Gramenz: maybe its some useful info
[16:48:18] Tomas Liubinas: @Sarunas: you are arguing about the same thing. The 
fact is that you can't mock singelton. And yes you can modify it, but I guess 
the Registry does exactly this.
[16:52:35] [ox] Sarunas Valaskevicius: actually, I was not arguing :) 
just noting the diferences between two approaches if using for just unit 
testing (because shop does not override oxconfig instance). 
current impl is singleton, the question was - why would registry be better for 
shop oxconfig class. (and got answer - coupling)
[16:53:50] [ox] Erik Kort: Yes ...Now dont get into a singleton jihad and rip 
them out everywehre were you see them :) .... Slowly and easy .. refactor when 
the need arise .. getting a singleton out is more a design issue then as an 
testing issue .. if you have a singleton in shop who you need to test _now_ .. 
and if its not about to refactored today, use Sarnunas way of testing .. .. If 
you are refactoring something and this class architecural would change anyway 
.... think of getting  the singleton out of it. ... BTW We dont have a Registry 
yet in shop, do we ? ..
[16:55:15] Tomas Liubinas: we don't
[16:58:33] [ox] Erik Kort: so lets keep that in mind and define what kind of 
regsitry would be good for the shop .. .. Lets discuss that another time ;)
[17:04:28] Tomas Liubinas: ack


> -----Original Message-----
> From: [email protected] 
> [mailto:[email protected]] On Behalf Of 
> Christopher Simon
> Sent: Friday, August 14, 2009 4:24 PM
> To: [email protected]
> Subject: Re: [oxid-dev-general] oxSuperCfg
> 
> Hi Tomas,
> 
> I think Singletons are definetly the State of the Art method 
> to implement this functionality.
> 
> Improvements compared to inherited methods from "god class":
> 
> + no methods where they shouldn't be ($oOrder->isAdmin() <- makes no 
> + sense) free "namespaces" for method names and therefore:
> + intuitive interface $oOrder->getUser() should user which made the 
> + order
> 
> Could you explain why your decision did go "pro" oxSuperCfg?
> 
> 
> Tomas Liubinas wrote:
> > Hi Christopeher,
> > 
> > This oxSuperCfg() is a result of long internal discussions. 
> Personally 
> > I would agree that the way it is implemented now is not 
> perfect, and 
> > sometimes as you say could be avoided at all. In most cases 
> you could 
> > use singelton getInstance() instead of dynamic (non static?)
> > ->getConfig(). However one could argue should we use 
> singeltons at all?
> > 
> > Regards
> > Tomas Liubinas
> > 
> > -----Original Message-----
> > From: [email protected]
> > [mailto:[email protected]] On Behalf Of 
> > Christopher Simon
> > Sent: Friday, August 14, 2009 12:35 PM
> > To: [email protected]
> > Subject: [oxid-dev-general] oxSuperCfg
> > 
> > Hi,
> > 
> > nearly every class is a child of oxSuperCfg.
> > 
> > It can be confusing anyway. Here is a example:
> > 
> > <snip>
> > $oOrder = oxNew('oxorder');
> > 
> > $oOrder->load($oxid); // just for example, imagine that we have 
> > retrieved the orders oxid from somewhere
> > 
> > $orderUser = $oOrder->getUser();
> > </snip>
> > 
> > What is returned by getUser()?
> > 
> > It's not the user which made the order - like a lot of people would 
> > expect - its the active user.
> > 
> > Which makes no sense on this object.
> > 
> > In general, all methods in oxSuperCfg are completly redundant:
> > 
> > - getConfig(): returns result of singleton oxConfig::getInstance()
> > 
> > - getSession(): returns result of oxSession::getInstance()
> > 
> > - getUser(): returns oxUser::loadActiveUser which could be 
> implemented 
> > as static method on user object
> > 
> > - isAdmin(): the result is defined as global function in 
> oxfunctions, 
> > and it's a config parameter named "blAdmin" anyway.
> > 
> > the unit test functionality of these methods could be 
> implemented in 
> > this singletons or static functions. there is no need to have 
> > oxSuperCfg, also because it's no "cfg" or "config" anyway.
> > 
> > In addition, not every object needs those methods, but every object 
> > has those methods, at the moment.
> > _______________________________________________
> > dev-general mailing list
> > [email protected]
> > http://dir.gmane.org/gmane.comp.php.oxid.general
> > _______________________________________________
> > dev-general mailing list
> > [email protected]
> > http://dir.gmane.org/gmane.comp.php.oxid.general
> 
> _______________________________________________
> dev-general mailing list
> [email protected]
> http://dir.gmane.org/gmane.comp.php.oxid.general
> 
_______________________________________________
dev-general mailing list
[email protected]
http://dir.gmane.org/gmane.comp.php.oxid.general

Reply via email to