> 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 



-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to