# RFC: Custom Factories (SPL)

- Thread: https://externals.io/message/46080
- Original archive: https://news-web.php.net/php.internals/46080
- Started by Robert Lemke on 2009-11-18T16:06:53+00:00
- Messages: 16
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #46080 — Robert Lemke — 2009-11-18T16:06:53+00:00

URL: https://externals.io/message/46080#46080

Hi folks,

after discussing the idea with various PHP developers I now felt safe enough that it's not a completely stupid idea to post an RFC for it. The idea is to add support the registration of custom factories which are responsible for instantiating certain classes.

Here is the first draft of my RFC:
http://wiki.php.net/rfc/customfactories

I suggest that we first discuss the implications and usefulness of this feature. In a second step I'd need to find some skilled internals wizard who can implement it, because not being a C developer myself, all I can offer is making suggestions and fine coffee.

Looking forward to hearing your comments!
Robert

-- 
Robert Lemke
Fluent Code Artisan

Lead Developer TYPO3 5.0 and FLOW3
TYPO3 Association co-founder

http://typo3.org
http://flow3.typo3.org
http://association.typo3.org

---

## #46081 — Alexey Zakhlestin — 2009-11-18T16:27:54+00:00

URL: https://externals.io/message/46080#46081 · In reply to: #46080

> Hi folks,
> 
> after discussing the idea with various PHP developers I now felt safe enough that it's not a completely stupid idea to post an RFC for it. The idea is to add support the registration of custom factories which are responsible for instantiating certain classes.
> 
> Here is the first draft of my RFC:
> http://wiki.php.net/rfc/customfactories
> 
> I suggest that we first discuss the implications and usefulness of this feature. In a second step I'd need to find some skilled internals wizard who can implement it, because not being a C developer myself, all I can offer is making suggestions and fine coffee.
> 
> Looking forward to hearing your comments!

So, from the high-level point of view, you want to introduce mechanism, which would allow instantiate objects by their interface, instead of their class-name.
And this mechanism should use user-provided rules for choosing appropriate implementation.

---

## #46083 — Etienne Kneuss — 2009-11-18T17:00:23+00:00

URL: https://externals.io/message/46080#46083

Hello,

On Wed, Nov 18, 2009 at 5:54 PM, Mathieu Suen <mathieu.suen@easyflirt.com>wrote:

> Robert Lemke a écrit :
>
>  Hi folks,
> > […]
>
> An other way maybe to allow this:
>
> $email = new $emailClassName();
>
>
>
This is already allowed.

Best,


> -- Mathieu Suen
>
>
>
> --
> 
> 
>
>


-- 
Etienne Kneuss
http://www.colder.ch

---

## #46084 — Robert Lemke — 2009-11-18T17:17:55+00:00

URL: https://externals.io/message/46080#46084 · In reply to: #46081

Hi Alexey,

Am 18.11.2009 um 17:27 schrieb Alexey Zakhlestin:

> So, from the high-level point of view, you want to introduce mechanism, which would allow instantiate objects by their interface, instead of their class-name.
> And this mechanism should use user-provided rules for choosing appropriate implementation.


well, using interface was just an example, we'd need the ability to instantiate classes as well by custom factories. I tried to clarify this by an updated example:

class Foo {
	public function bar() {
			// Instantiate by class name:
		$email = new Email();
			// or even instantiate by interface name (the factory needs to find the right implementation):
		$email = new EmailInterface();
	}
}

So in the end the custom factory needs to find an appropriate implementation for EmailInterface.

Cheers,
robert

-- 
Robert Lemke
Fluent Code Artisan

http://typo3.org
http://flow3.typo3.org

---

## #46086 — Robert Lemke — 2009-11-18T17:27:07+00:00

URL: https://externals.io/message/46080#46086

Hi Mathieu,

Am 18.11.2009 um 18:19 schrieb Mathieu Suen:

> Right!!
> I get confused with:
> $classNamme::getInstance();
> 
> So you can easily inject dependency:
> 
> class Foo {
> 
> 	protected $emailer;
> 
> 	public function __construct($emailClass) {
> 		$this->emailer= $emailClass;
> 	}
> 
> 	public function bar() {
> 		// $email = new $this->emailer(); Of course not allowed
> 		$emailer = $this->emailer;
> 		$email = $emailer();
> 		// ...
> 	}
> }

Well, this won't work, because Foo surely doesn't have all the knowledge to automatically resolve dependencies for the Email implementation. What if Email needs some SMTP Service injected? Foo won't know.

Therefore it's much better to let some specialized Object Factory to do the task. Letting Foo instantiate an Email would be asking a car to build its engine. Better delegate that task to a factory ...

Cheers,
robert

---

## #46087 — Eloy Bote Falcon — 2009-11-18T17:41:28+00:00

URL: https://externals.io/message/46080#46087

2009/11/18 Mathieu Suen <mathieu.suen@easyflirt.com>

> Etienne Kneuss a écrit :
>
> Hello,
> > […]
>
> Right!!
> I get confused with:
> $classNamme::getInstance();
>
> So you can easily inject dependency:
>
> class Foo {
>
>        protected $emailer;
>
>        public function __construct($emailClass) {
>                $this->emailer= $emailClass;
>        }
>
>        public function bar() {
>                // $email = new $this->emailer(); Of course not allowed
>                $emailer = $this->emailer;
>                $email = $emailer();
>                // ...
>
>        }
> }
>
> -- Mathieu Suen
>

Well, $email = new $this->emailer(); it's allowed too, and behaves as
expected since FOO::emailer it's a string.


Reagards,

Eloy Bote.

---

## #46089 — Stanislav Malyshev — 2009-11-18T19:43:42+00:00

URL: https://externals.io/message/46080#46089 · In reply to: #46080

Hi!

> Here is the first draft of my RFC:
> http://wiki.php.net/rfc/customfactories

Something I'm missing in this RFC: what's wrong with factory base class 
doing:

	public static function getInstance() {
		if(static::$instance === NULL) {
			static::$instance = new static;
		}
		return static::$instance;
	}

instead of "new self", and then the client class doing:

$this->logger = WhateverLogger::getInstance();

or even:

$clientLogger = $this->config['logger'];
$this->logger = $clientLogger::getInstance();

Also, the whole thing, whatever it is, looks like something one would do 
in user space in a framework, not on language level.
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #46093 — mm w — 2009-11-18T22:02:17+00:00

URL: https://externals.io/message/46080#46093 · In reply to: #46080

what you call factory objects are "more" proxy objects, please make
the difference, semantics are sometimes important.
anyway , what I can read this document is a bit a mess, it needs to be
split by "topic", your approach is really confuse.


Best,


> Hi folks,
>
> after discussing the idea with various PHP developers I now felt safe enough that it's not a completely stupid idea to post an RFC for it. The idea is to add support the registration of custom factories which are responsible for instantiating certain classes.
>
> Here is the first draft of my RFC:
> http://wiki.php.net/rfc/customfactories
>
> I suggest that we first discuss the implications and usefulness of this feature. In a second step I'd need to find some skilled internals wizard who can implement it, because not being a C developer myself, all I can offer is making suggestions and fine coffee.
>
> Looking forward to hearing your comments!
> Robert
>
> --
> Robert Lemke
> Fluent Code Artisan
>
> Lead Developer TYPO3 5.0 and FLOW3
> TYPO3 Association co-founder
>
> http://typo3.org
> http://flow3.typo3.org
> http://association.typo3.org

---

## #46094 — Jared Williams — 2009-11-19T02:24:01+00:00

URL: https://externals.io/message/46080#46094 · In reply to: #46080

> -----Original Message-----
> From: Robert Lemke [mailto:robert@typo3.org] 
> Sent: 18 November 2009 16:07
> To: internals@lists.php.net
> Subject: [PHP-DEV] RFC: Custom Factories (SPL)
> 
> Hi folks,
> 
> after discussing the idea with various PHP developers I now 
> felt safe enough that it's not a completely stupid idea to 
> post an RFC for it. The idea is to add support the 
> registration of custom factories which are responsible for 
> instantiating certain classes.
> 
> Here is the first draft of my RFC:
> http://wiki.php.net/rfc/customfactories
> 
> I suggest that we first discuss the implications and 
> usefulness of this feature. In a second step I'd need to find 
> some skilled internals wizard who can implement it, because 
> not being a C developer myself, all I can offer is making 
> suggestions and fine coffee.
> 
> Looking forward to hearing your comments!
> Robert
> 
> --
> Robert Lemke
> Fluent Code Artisan
> 

Whilst I am a fan of IoC, I don't think its desirable to add language
features just to make legacy code more flexible. 
Surely the route to take is to refactor the legacy code as and when
the extra flexibility is needed.

Also seems like a possible whole heap of wtf?! When a seemingly
absolute statement $a = new A(); gets mangled behind the scenes.

Jared

---

## #46096 — Alban — 2009-11-19T03:45:46+00:00

URL: https://externals.io/message/46080#46096 · In reply to: #46094

Le Thu, 19 Nov 2009 02:24:01 +0000, Jared Williams a écrit :

> > […]
> Whilst I am a fan of IoC, I don't think its desirable to add language
> features just to make legacy code more flexible. Surely the route to
> take is to refactor the legacy code as and when the extra flexibility is
> needed.
> 
> Also seems like a possible whole heap of wtf?! When a seemingly absolute
> statement $a = new A(); gets mangled behind the scenes.
> 
> Jared

I'm totaly agree with you Jared !
I'm a fan of IoC too.

A factory can provide an object by creating an instance of a class, the 
choice of the class depends of some paramters. Those parameters can be 
provided directly by the programmer but also by a final user.
PHP can not simply "choose" the class to instanciate by checking class's 
interfaces.

What Robert Lemke wants to implement is called a "Service" or a 
"Container". 
You register a service and call the service instead of calling a class 
directly. 

Let me show it in an example of session registration :

// you register the service
Services::register('session', 'sessionStoredInCookie');

// and call it
$session = Services::load('session');

Tomorrow, if you want change the session registration mechanism, for 
storing them in a database for exemple, you have just to change the 
registred service and whole application has change its session 
registration method :

// you register the service
Services::register('session', 'sessionStoredInDatabase');

This is very well treated by Fabien Potencier in this document : http://
fabien.potencier.org/talk/20/decouple-your-code-for-reusability-php-
forum-2008?position=41 (some parts are in french)

Implementing a service or container mechanism could be very simple or 
very complicated. Fabien Potencier use a very complicated example in the 
link above.

Use a service or container mechanism (and its implementation) is a 
developper choice. this could not be traced by php core.

A service (or container) can create an instance of class or just return 
an instance of class which is allready created.

// you register the service
Services::register('databaseConnexion', new databaseConnexionFactory
('mysql', array('server', 'database', 'user', 'password')));

// and call it
$db = Services::load('databaseConnexion');

How PHP should treat the singleton ? getInstance() is just a convention. 
Create a service mechanism directly in php implies that php implements 
singleton model too.

-- 
Alban Leroux seza@paradoxal.org

---

## #46098 — Eloy Bote Falcon — 2009-11-19T09:10:14+00:00

URL: https://externals.io/message/46080#46098

2009/11/19 Mathieu Suen <mathieu.suen@easyflirt.com>

> Eloy Bote Falcon a écrit :
>
> 2009/11/18 Mathieu Suen <mathieu.suen@easyflirt.com>
> > […]
>
> I have tested in php 5.2 is that a feature added in 5.3?
>
>
> > […]
>
> --
>
>
> • *Mathieu Suen* | It Team | www.easyflirt.com
> • mathieu [dot] suen [at] easyflirt [dot] com
> • EasyFlirt - Park Nord, Les Pléiades, 74370 - Metz-Tessy - FRANCE
>
>
> • Pensez à l'environnement, n'imprimez cet e-mail qu'en cas de réelle
> nécessité
>
>
>


Yes it is.

Returning to the topic, I don't think that these kind of features should be
implemented in the PHP core...let's focus in other interesting features like
traits; a new wide range of possibilities will open and the (not so) new
programming paradigms like AOP or SOP could be powerfully and easily
implemented by the end users.


Regards,

Eloy Bote.

---

## #46099 — Mathieu Suen — 2009-11-19T11:06:19+00:00

URL: https://externals.io/message/46080#46099 · In reply to: #46096

Alban a écrit :
> Le Thu, 19 Nov 2009 02:24:01 +0000, Jared Williams a écrit :
> 
> > […]
> 
> I'm totaly agree with you Jared !
> I'm a fan of IoC too.
> 
> A factory can provide an object by creating an instance of a class, the 
> choice of the class depends of some paramters. Those parameters can be 
> provided directly by the programmer but also by a final user.
> PHP can not simply "choose" the class to instanciate by checking class's 
> interfaces.
> 
> What Robert Lemke wants to implement is called a "Service" or a 
> "Container". 
> You register a service and call the service instead of calling a class 
> directly. 
> 
> Let me show it in an example of session registration :
> 
> // you register the service
> Services::register('session', 'sessionStoredInCookie');
> 
> // and call it
> $session = Services::load('session');
> 
> Tomorrow, if you want change the session registration mechanism, for 
> storing them in a database for exemple, you have just to change the 
> registred service and whole application has change its session 
> registration method :
> 
> // you register the service
> Services::register('session', 'sessionStoredInDatabase');
> 
> This is very well treated by Fabien Potencier in this document : http://
> fabien.potencier.org/talk/20/decouple-your-code-for-reusability-php-
> forum-2008?position=41 (some parts are in french)
> 
> Implementing a service or container mechanism could be very simple or 
> very complicated. Fabien Potencier use a very complicated example in the 
> link above.
> 
> Use a service or container mechanism (and its implementation) is a 
> developper choice. this could not be traced by php core.
> 
> A service (or container) can create an instance of class or just return 
> an instance of class which is allready created.
> 
> // you register the service
> Services::register('databaseConnexion', new databaseConnexionFactory
> ('mysql', array('server', 'database', 'user', 'password')));
> 
> // and call it
> $db = Services::load('databaseConnexion');
> 
> How PHP should treat the singleton ? getInstance() is just a convention. 
> Create a service mechanism directly in php implies that php implements 
> singleton model too.
> 

Some language have support for IoC. See newspeak:
http://gbracha.blogspot.com/2009/07/ban-on-imports-continued.html


-- Mathieu Suen

---

## #46102 — Ionut G. Stan — 2009-11-19T14:48:30+00:00

URL: https://externals.io/message/46080#46102 · In reply to: #46080

This smells like metaclasses to me, just that in your RFC they are 
supposed to work on a global level, not on a per class level.

Python, for example, has a magic method called `__new__`, which controls 
the creation of the object whenever a new class is instantiated. It 
actually allows you to return a different object than the expected one.

I somehow like the proposal, but it may create havoc in some code bases. 
I wouldn't really want to see `new FooBar`, when it actually means a 
`DamnBar`.

There are also other things to take into consideration. You may want to 
override this instantiation mechanism for `FooBar` just in a single 
class, not in all of them, which complicates the problem. You'd have to 
received the scope where the instantiation is done, but even then, there 
may be no way to really know which *object*, not class, wants to 
instantiate `FooBar`.

I agree IoC is necessary, but I'm not really sure this is the way to go.

... [some thinking]

At this point, in PHP, classes are global constant symbols. Allowing us 
to override the instantiation mechanism would make them global variable 
symbols. The below example is already possible in PHP and I believe it 
already does what you're asking for (in the current RFC):


class Emailer
{}

$Emailer= 'Emailer';

class FooBar
{
	public function sendEmail()
	{
		global $Emailer;

		$emailer = new $Emailer;
	}
}



> Hi folks,
>
> after discussing the idea with various PHP developers I now felt safe enough that it's not a completely stupid idea to post an RFC for it. The idea is to add support the registration of custom factories which are responsible for instantiating certain classes.
>
> Here is the first draft of my RFC:
> http://wiki.php.net/rfc/customfactories
>
> I suggest that we first discuss the implications and usefulness of this feature. In a second step I'd need to find some skilled internals wizard who can implement it, because not being a C developer myself, all I can offer is making suggestions and fine coffee.
>
> Looking forward to hearing your comments!
> Robert
>

-- 
Ionut G. Stan
I'm under construction  |  http://blog.igstan.ro/

---

## #46105 — Ionut G. Stan — 2009-11-19T15:07:27+00:00

URL: https://externals.io/message/46080#46105

One could just as well pass an instance of Emailer to the constructor. 
It's the same thing, except that it's less code (and it's easier to 
understand in my opinion).

It's a basic application of the Law of Demeter.


>
> Right!!
> I get confused with:
> $classNamme::getInstance();
>
> So you can easily inject dependency:
>
> class Foo {
>
> protected $emailer;
>
> public function __construct($emailClass) {
> $this->emailer= $emailClass;
> }
>
> public function bar() {
> // $email = new $this->emailer(); Of course not allowed
> $emailer = $this->emailer;
> $email = $emailer();
> // ...
> }
> }
> -- Mathieu Suen

-- 
Ionut G. Stan
I'm under construction  |  http://blog.igstan.ro/

---

## #46108 — Alban — 2009-11-19T17:06:18+00:00

URL: https://externals.io/message/46080#46108 · In reply to: #46099

Le Thu, 19 Nov 2009 12:06:19 +0100, Mathieu Suen a écrit :

> Alban a écrit :
> > […]
> Some language have support for IoC. See newspeak:
> http://gbracha.blogspot.com/2009/07/ban-on-imports-continued.html
> 
> 
> -- Mathieu Suen

That's a good idea to add support of IoC in PHP. 
But i think a mechanism like spl_autoloader doesn't sounds very well.

I prefer see a mechanism like import/export, something like this :

-- file a.php --

import B

class A {
    public function hello() {
        $b = new B();
        $b->hello();
    }
}

-- file myB.php --

class myB {
    public function hello() {
        echo "Hello, I'm myB";
    }
}

-- file otherB.php --

class myB {
    public function hello() {
        echo "Hello, I'm otherB";
    }
}

-- file main.php --

require_once 'a.php';
require_once 'myb.php';
require_once 'otherb.php';

export myB as B;

$a = new A();
$a->hello(); // print : "Hello, I'm myB";

export otherB as B;

$a->hello(); // print : "Hello, I'm otherB";

This is like the 'use' command for class alias, at the difference that 
the 'use' command works localy and it resolved at the compilation time.

-- 
Alban Leroux seza@paradoxal.org

---

## #46117 — jvlad — 2009-11-19T23:38:44+00:00

URL: https://externals.io/message/46080#46117 · In reply to: #46080

> Hi folks,
>
> after discussing the idea with various PHP developers
> I now felt safe enough that it's not a completely stupid
> idea to post an RFC for it. The idea is to add support
> the registration of > custom factories which are
> responsible for instantiating certain classes.
>
> Here is the first draft of my RFC:
> http://wiki.php.net/rfc/customfactories

Robert,
Slightly different idea, why not to generalize the way of class-load and
class-instantiation in php and make existing auto-load feature implemented
as a part of it? It should be flexible enough and allow to work with 
auto-loading files and/or
factories to be called for the class instance.
Class instantiation is an important thing itself and PHP should support 
certain
interface for this. So all the factories will have at least one common 
interface.

Similar stuff works great in Mozilla (XPCOM) and MS' COM.
I mean IFactory and nsIFactory:

interface nsIFactory :  nsISupports {
   /**
    * Creates an instance of a component.
    *
    * @param aOuter Pointer to a component that wishes to be aggregated
    *               in the resulting instance. This will be nsnull if no
    *               aggregation is requested.
    * @param iid    The IID of the interface being requested in
    *               the component which is being currently created.
    * @param result [out] Pointer to the newly created instance, if 
successful.
    * @return NS_OK - Component successfully created and the interface
    *                 being requested was successfully returned in result.
    *         NS_NOINTERFACE - Interface not accessible.
    *         NS_ERROR_NO_AGGREGATION - if an 'outer' object is supplied, 
but the
    *                                   component is not aggregatable.
    *         NS_ERROR* - Method failure.
    */
    void createInstance(in nsISupports aOuter, in nsIIDRef iid,
                      [retval, iid_is(iid)] out nsQIResult result);

   /**
    * LockFactory provides the client a way to keep the component
    * in memory until it is finished with it. The client can call
    * LockFactory(PR_TRUE) to lock the factory and LockFactory(PR_FALSE)
    * to release the factory.
    *
    * @param lock - Must be PR_TRUE or PR_FALSE
    * @return NS_OK - If the lock operation was successful.
    *         NS_ERROR* - Method failure.
    */
    void lockFactory(in PRBool lock);
};


similar thingy can be found in COM.


In PHP terms it'd be much easier:

interface IFactory... {
  /**
  * @returns mixed class instance initialized with default constructor
  * @except throws descendant of EFactory exception in case of errors
  */
  function CreateInstance();
}

/**
 * @desc nothing new in this class except its class name  that can be used 
for filtering exceptions in catch()
 */
class EFactory extends Exception {};


Regarding your sample, "class SystemLogger implements LoggerInterface" is 
nothing more but a classic singleton. It creates
one and only one instance and always return it.
In terms of XPCOM or COM it can be created with appropriate flags used in 
the factory template. See SINGLETON
attribute in mozilla sources. While the factory is a standalone instance or 
static class that can only create instances or
instance of another certain class. For example LoggerFactory would create 
SystemLogger instances (instance).
This is proven technology and works good for more than 10 years.

Regarding such contructs like $this->logger->log() in SomeService,
it's known that many classes are partially or wholly wrappers around one or 
many instances in them.
With SomeService, one can introduce log method in it like:
class SomeService {
...
log($msg) {
  $this->logger->log($msg)
}
}
and call $this->log() instead of $this->logger->log(), as it's shorter and 
more readable.
But in cases when inner instance have many methods to be wrapped, such dummy 
code
may waste too much space.
So I'd propropose to implement a "delegate calls to instance" feature. It 
may look like below
delegate_calls($delegator, $delegatee, $interface).

For example
delegate_calls($this, $this->logger, LoggerInterface)
can be called and after that you'll call any methods defined in 
LoggerInterface interface
with $this instance but in fact method in $this->logger will be called.
Such delegation would simplify sources:
$this->log('aMethod has been called.');
instead of
$this->logger->log('aMethod has been called.');


I know, __call() can be used to delegate calls too, but with this way I'd 
have to intercept __call and repeat
the same method body each time I need delegation.

-jv
