Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Registry Component Proposal

Proposed Component Name Zend_Registry
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Registry
Proposers Art Hundiak
Gavin (Zend-liaison)
Revision 1.1 - 20 June 2006: Initial Submission.
1.2 - 23 July 2006: Incorporate some of the comments
1.3 - 26 July 2006: Source code posted (wiki revision: 19)

Table of Contents

1. Overview

Zend_Registry uses a dynamic object to provide a means of sharing other objects between different portions of an application.

2. References

  • Symfony
  • Pretty much every other oop framework out there

3. Component Requirements, Constraints, and Acceptance Criteria

  • Use a dynamic extendable object to share other objects between modules.
  • Replaces the existing procedural registry system while maintaining a simple static interface.

4. Dependencies on Other Framework Components

  • Zend_Exception

5. Theory of Operation

The current framework uses several procedural functions (Zend::register,Zend::registry,Zend::isRegistered). At the risk of creating a strawman, I think the reason for choosing this approach was the perceived simplicity. No object needs to be created nor does one need to pass around this object since the functions are globally accessible.

The disadvantage of course is that the developer is locked into a very simplistic model with no easy way of customizing things to suit their particular applications. For example, in the current Zend:register function the code checks to see if a given object has already been registered and, if so, throws an exception. Now most developers won't care. They don't intend to register the same object more than once. Of those that do care, some developers might want this check while other will not. The current implementation means that developers will just have to live with whatever the frame work folks have decided is the answer.

On the other hand, we could just create an object which implements a standard Zend_Registry_Interface and pass this object onto the front controller which in turn makes sure that the plugins and cntroller classes all receive the object as an argument. A reference implementation of Zend_Registry provides default behaviour for most applications while leaving the developer free to implement their own object if required. And since the object just becomes a protected instance variable then it's really no more difficult to use than the current static methods.

Use of a registry object also allows the developer to add significant new functionality if needed. Consider for example the question of how to create the objects that the registry contains. In the simple approach you need some code somewhere to create your config, session, db etc objects. But with a registry object, the registry class itself can create the necessary objects on demand. So you end up with an application specific registry object (call it a service locator or application context object if you like) which contains methods for creating shared objects. When you do $view = $registry->view you actually end up executing a getView method which creates the view and sets all the directory paths and other options.

A dynamic registry object is also required for performing robust unit testing. With the current static approach, the unit testing code has no way to simply clear the registry and start over again. With a dynamic approach, each test can create a new registry and pass it on to the object being tested.

6. Milestones / Tasks

zone: Missing {zone-data:milestones}

7. Class Index

  • Zend_Registry
  • Zend_Registry_Interface
  • Zend_Registry_Exception

8. Use Cases

9. Class Skeletons

Working code with tests is available from: http://zayso.org/zendfw/index.html

Existing code which relies on Zend::registry static functions will work unchanged.

Users can specify a different registry class during the bootstrap process with:
Zend_Registry::setInstance(new Some_Other_Registry_Class);
And still access it with the Zend static functions.

Unit testers can also use setInstance to start over with a new registry.

The real fun comes in trying to inject the registry into the core classes to eliminate
the need for a global static registry. Basically want to modify certain classes to
allow passing a registry to their constructors and then having the objects in turn pass them
onwards to objects they create. The dispatch/controller is a good example.

So it's pretty easy to send the registry to the controller by creating a dispatcher with it. And it should not upset existing code.

Of course we would also like to have the registry passed to some of the other MVC classes. The Zend_Controller_Router classes currently have empty constructors so it would be easy to pass the registry on to it. It in turn should pass it on to the individual Route objects in case someone wants to do something fancy in routing.

The plugin classes also have empty constructors so adding $registry to them would be easy.

The Zend_View implementation is bit different as it currently takes an array as an argument. Personally, I think the array argument should be dropped just to make it more consistent with the rest of the MVC classes. Not sure how much current app code uses the constructor config method. In any event, registry could be added as an array argument(bad) or could just add it as the first argument to the view construcor(good).

And the view should then pass it on to the view helpers. Probably as public instance just to avoid having a base view class.

It would also be nice to have registry available to the front controller. But the private constructors and final methods make it clear that the front controller is off limits to application code. If we ever opened up the front controller then we could add the registry. Till then, requiring the application to set the dispatcher and/or router objects is acceptable.

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jun 21, 2006

    <p>I think a dynamic Registry would be one of the best change that could be make at this point. My guess is that the current static Registry will come back to bite the ZF in the long run. It is a big inflexible block in the middle of everything. Injecting a Registry object similar to the current Zend class into the controllers would be small change producing a great benefit.</p>

    <p>However, I would stay away from the kind of Context object that many frameworks use. Though useful it is limiting by definition. It would make the ZF inflexible to different styles on implemention. I think a flexible, configurable Service Locator is much more in the ZF spirit of simplicity and 80/20.</p>

    <p>Here is a link to the classic article about Dependency Injection: <a href="http://www.martinfowler.com/articles/injection.html">http://www.martinfowler.com/articles/injection.html</a></p>

    1. Jun 21, 2006

      <p>Agree 100% that Zend should not have a context object. A simple registry object that is passed around is all that I am looking for. The developer can then extend it as far as they want for their own application.</p>

  2. Jun 21, 2006

    <p>Okay, I've thought more about it and I've come around. The unit testing argument is a strong one.</p>

    <p>Another issue that people might come across in the future is one in which you have a ZF-based application and attempt to integrate some outside ZF-based functionality into your application. This way, it will be able to create and manage its own registry independent of yours. Otherwise, it has to define its own objects in a separate class using a poor man's namespace (Zend::register("myapp_whatever")). In either case, it would have to instantiate the object at the beginning of every action.</p>

    <p>The one requirement I would keep is that objects are the only things allowed to be stored. It might be tempting for some developers to use it in lieu of explicit globals otherwise.</p>

  3. Jun 21, 2006

    <p>I would prefer injecting the current Zend class or something very similar into the controllers than a creating a different Registry class. </p>

    1. Jun 22, 2006

      <p>Why? The other methods in the Zend class deal with loading files and dumping variables for debugging. To me they seem to be unrelated to the notion of a registry.</p>

      1. Jun 22, 2006

        <p>As I said, my preference is for a Service Locator which is essentially a Registry plus a class loader. That is what the current Zend class is. There is currently a good implementation. I just want to inject it. </p>

        <p>The extra dump() method is handy – it is only one small method, I can take it or leave it. </p>

        1. Jun 22, 2006

          <p>Not sure that I would agree that a Service Locator is just a registry + class loader. I think a class loader just finds the correct php file based on the name of the class whereas a Service Locator actually determines which class to create and how to initialize it.</p>

          <p>On the other hand, as long as we can get the Zend folks to agree to inject something then I'll be happy. </p>

  4. Jun 22, 2006

    <p>I don't think passing around registry object is a good idea. However, using Zend::register interface does not require using any specific registry class with any specific behaviour - so we can add possibility to override it (e.g. with Zend::setRegistry(Zend_Registry_Interface newRegistry)) on need.</p>

    <p>And I think having global static registry is actually a good thing - for some implementations that really do need to pass global data around and want a way to organise it beyond using globals. </p>

    1. Jun 22, 2006

      <p>Why is passing around a registry object not a good idea? Specifics please.</p>

      <p>I don't really care for the notion of adding a setRegistry method. Seems to complicate things. If we can't get the front controller to pass around a registry object then I'll just use the existing registry code to simulate it.</p>

      <p>$context = new ApplicationContext();<br />
      Zend::register('context',$context);<br />
      ...</p>

      1. Jun 22, 2006

        <p>There are many arguments against using static classes – testing being one, but there are several others. </p>

        <p>For me the main problem is that once you put Zend::* into code it is irreplaceable. Once placed in the code it cannot be extended without changing the static call. Whereas if you inject a Registry object as $registry->* then the application can enhance the Zend class as needed. </p>

        <p>Currently the Zend class in only called statically in a few places in the framework. Most of those are loadClass() calls that could easily be replaced (Dispatcher, Db, Json, Mime_Part). Changing these to simple includes (or using the injected registry) would be trivial and easy to do now. </p>

        <p>The Dispatcher also calls isReadable() but because the Registry would be injected the Dispatcher would have full access to it anyway, so the change there is trivial as well. </p>

        <p>DB_Table calls Zend::registry() in the constructor, and I would suggest that this is a poor design to try to provide a safety net there for something that should be handled elsewhere. </p>

        <p>So my summary is that injecting the Registry would be of long term benefit and that making the change would be very easy at this point. </p>

    2. Jun 22, 2006

      <p>I think once we start getting to the point where there are more methods in the base class relating to the registry than anything else (register, registry, isRegistered, setRegistry), it is probably time to think about splitting it off anyway.</p>

      <p>Truly global data should be put in a config file.</p>

  5. Jun 22, 2006

    <p>Tracking the registry and constantly trying to pass it around in the manner suggested would become cumbersome.</p>

    <p>Is every class going to be like your code where it has to be passed through every single class function? Wouldn't it be better to handle once during construct and access using something like $this->registry</p>

    <p>The example provided to use the interface, what If I need the database across multiple classes, your example is going to recreate the factory every single time I call getDB.</p>

    <p>Honestly I do like the idea of making the registry more flexable, The theory is sound and I would love to put hooks in so instead of preloading everything I could do more loading on demand but from the use cases and examples I see here this is not the way to do it.</p>

    1. Jun 22, 2006

      <p>In the example provided, getDb is a protected function and would only be called the first time that db is requested.</p>

      <p>As far as it being cumbersome to pass around $registry, it's really not all that bad. The framework can ensure that the controller actions are passed the registry so the programer does not have to do too much.</p>

      <p>It could be added as an instance variable but that means that the constructor needs to know about it. I guess it's really a question of taste. I'd rather pass it around but could be convinced otherwise.</p>

      1. Jun 26, 2006

        <p>Say I'm updating a database with every successful route in a controller plugin (post-dispatch). How would I be able to access the registry object there?</p>

        1. Jun 26, 2006

          <p>It would be up to the front controller to ensure that the registry was passed to all the downstream objects. I have not looked at the plugin system in any real detail (especially since the manual is still empty) but I'm assuming that whatever actually ends up executing the plugin methods will have access to the registry.</p>

        2. Jun 26, 2006

          <p>WThe Front Controller would pass the Registry as the parameter to all Action Controllers. So if you had a Controller plugin, you could register it with the Registery at the same time that you registered it with the Front Controller or Router. It would be directly accessable. Any object you wanted to inject would be directly available in the Action Controller. You could also mock that Filter while you were building things and access the mock identically. </p>

          <p>Alternatively, the Front Controller may automatically register itself with the Registry (that could be a convention) and then you could get the Front Controller from the Registry and in turn get the plugin from the Front Controller. </p>

          <p>I know some programmers complain about the extra line of code to get objects from the Registry, but I find providing dependency injection in a consistent manner far outweighs that. </p>

          1. Jun 26, 2006

            <blockquote>
            <p>The Front Controller would pass the Registry as the parameter to all Action Controllers. So if you had a Controller plugin, you could register it with the Registery at the same time that you registered it with the Front Controller or Router. It would be directly accessable. Any object you wanted to inject would be directly available in the Action Controller. You could also mock that Filter while you were building things and access the mock identically.</p></blockquote>

            <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
            $controller = Zend_Controller_Front::getInstance();
            $controller->setControllerDirectory($controllerDirectory);
            $controller->setRegistry($registry);
            $controller->registerPlugin(new SomePlugin());
            $controller->dispatch();
            ]]></ac:plain-text-body></ac:macro>

            <p>Ah, of course. Thanks for both of your replies.</p>

            1. Jun 26, 2006

              <p>Here it is with the current Zend class injected instead of as a horrid static.</p>

              <p>index.php</p>
              <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
              $plugin = new SomePlugin();

              $registry = new Zend();
              $registry->register('SomePlugin', $plugin);

              $controller = new Zend_Controller_Front($registry);
              $controller->registerPlugin($plugin);
              $controller->dispatch();
              ]]></ac:plain-text-body></ac:macro>

              <p>controller/indexController.php</p>
              <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
              class indexController {

              function indexAction($registry);

              $plugin = $registry->registry('SomePlugin');

              ...
              ]]></ac:plain-text-body></ac:macro>

              1. Aug 21, 2006

                <p><strong>brainstorm mode</strong> = on; # wacky ideas now permitted <ac:emoticon ac:name="wink" /></p>

                <p>What if the "backend" for registry was more like the backend that will be used for Zend_Session, Zend_Config, Zend_Acl, etc.? A typical, object-oriented container object offers numerous advantages, including namespacing, and methods to act on subtrees (e.g. namespaces) of objects in the container. Perhaps something to follow up for the next version of Zend_Registry, after the other issues have been solved by an implementation.</p>

  6. Jul 17, 2006

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Feedback</ac:parameter><ac:rich-text-body>
    <p>Conditionally accepted with the following changes required:</p>

    <ul class="alternate">
    <li>There must be a ZF system registry available statically and<br />
    globally for the entire ZF application.</li>
    </ul>

    <ul class="alternate">
    <li>The default getter and setter methods should be "final".</li>
    </ul>

    <ul class="alternate">
    <li>The registry should not provide a form of dynamic scoping by<br />
    having the instance passed into the Controller, and onward to <br />
    actions, etc.</li>
    </ul>

    <ul class="alternate">
    <li>Moving the registry out of Zend.php into a separate class is ok,<br />
    provided the registry is auto-created on first use, and provided that <br />
    the application developer has an extremely easy way to identify which <br />
    subclass of Zend_Registry (if any) should be used.</li>
    </ul>

    <ul class="alternate">
    <li>The "no duplicate objects" and "no duplicate entries with the same<br />
    key" must be enforced always (i.e. disallow subclasses overriding this <br />
    behavior).<br />
    If our search for answers to the post: <br />
    <a href="http://www.zend.com/lists/fw-general/200607/msg00482.html">Zend::registry() - Example Use Cases Wanted for the Manual</a><br />
    shows the community needs something different than above,<br />
    then that requirement should be reconsidered.</li>
    </ul>

    <p>The registry is intended for use solely by developers,<br />
    not for use within ZF core components, so feedback from those using<br />
    Zend::registry(), and alternatives are solicited.<br />
    Some might wish to submit a laboratory proposal, if they have<br />
    implemented their own registry or observer-like facility:
    <a class="external-link" href="http://framework.zend.com/wiki/display/ZFPROP/Home">http://framework.zend.com/wiki/display/ZFPROP/Home</a></p></ac:rich-text-body></ac:macro>

    1. Jul 19, 2006

      <ul>
      <li>There must be a ZF system registry available statically and<br />
      globally for the entire ZF application.</li>
      <li>Moving the registry out of Zend.php into a separate class is ok,<br />
      provided the registry is auto-created on first use, and provided that<br />
      the application developer has an extremely easy way to identify which<br />
      subclass of Zend_Registry (if any) should be used.</li>
      </ul>

      <p>What is the plan with these? It seems like either Zend_Registry should use Zend::registry internally or Zend::registry should use Zend_Registry internally. Which one should it be?</p>

      <ul>
      <li>The default getter and setter methods should be "final".</li>
      </ul>

      <p>Why?</p>

      <ul>
      <li>The registry should not provide a form of dynamic scoping by<br />
      having the instance passed into the Controller, and onward to<br />
      actions, etc.</li>
      </ul>

      <p>Can you clarify? Is this no to providing "dynamic scoping" or no to passing it through the Controllers?</p>

      1. Jul 19, 2006

        <blockquote><p>What is the plan with these? It seems like either Zend_Registry should use Zend::registry internally or Zend::registry should use Zend_Registry internally. Which one should it be?</p></blockquote>

        <p>Zend::registry should use Zend_Registry. This preserves the existing API and backward compatibility.</p>

        <blockquote><p>Why <ac:link><ri:page ri:content-title="final" /></ac:link>?</p></blockquote>

        <p>The decision for "final" getter and setter methods was made to address concerns about subclasses created by developers that incompatibility change the behavior of instances of the Zend_Registry subclass and breaking existing code written by developers.</p>

        <blockquote><p>Can you clarify? Is this no to providing "dynamic scoping" or no to passing it through the Controllers?</p></blockquote>

        <p>The instance should be global, and not passed down into Controllers and actions.<br />
        How developers use the registry is left to the developer.</p>

  7. Jul 20, 2006

    <p>Kind of sad to see the decision about global scoping since that was a main point of the proposal. Oh well. It's possible to inject it into the Controller classes anyways just not as clean as it would be if the system did it for you.</p>

    <p>As far as the actual functionality of the Registry class goes, let's define an interface as well as a default implementation. Put whatever restrictions you want on the default implementation. As long as a class supporting the interface can be used in place of the default class then all will be fine.</p>

    <p>So what's the next step here? </p>

    <p>Should someone propose a Registry Interface that we can hash out?</p>

    <p>From what I understand, replacing Zend::registry($name) is ok. Do we replace it with:</p>

    <p>a. Zend_Registry::getInstance()->get($name);<br />
    b. Zend_Registry::getInstance()->name;<br />
    c. Zend_Registry::get($name);</p>

    <p>I vote for b though we could support all three at the risk of bloat.</p>

    1. Jul 20, 2006

      <p>Art, we discussed your feedback, and various clarifications might help.</p>

      <p>Would you like to suggest an approach to modifying the existing Controller/Actions/etc., such that a single additional, but optional, parameter (e.g. $args) could be passed along? Something approaching a patch for trunk will help clarify more.</p>

      <p>If we can find a way to do this modification with <strong>no</strong> impact on existing ZF users and applications, and we keep the concept of a singleton global registry that is automatically available globally, then maybe we can implement something that is closer to the "main point of the proposal".</p>

      <p>If $args becomes an array of "pass-by-keyword" arguments, then $args could provide a mechanism for passing additional, dynamically instantiated, registries around.</p>

      1. Jul 21, 2006

        <p><strong>W</strong><strong>ould you like to suggest an approach to modifying the existing Controller/Actions/etc., such that a single additional, but optional, parameter (e.g. $args) could be passed along? Something approaching a patch for trunk will help clarify more</strong>.</p>

        <p>I'll take another look at it but a simple patch is not going to do it.  Passing along the registry will require touching mulitple classes and perhaps require changing a few other things as well.  Not sure if it worth the effort given that that the patch will probably not be committed. Sort of a chicken and egg effort.</p>

        <p><strong>If we can find a way to do this modification with no impact on existing ZF users and applications, and we keep the concept of a singleton global registry that is automatically available globally, then maybe we can implement something that is closer to the "main point of the proposal".</strong></p>

        <p>This is somewhat confusing.  I was under the impression that ZF was in a preview status.  Maybe we should start calling it Beta if the api is frozen.  In any event, no there should not be much impact on current apps.</p>

        <p><strong>If $args becomes an array of "pass-by-keyword" arguments, then $args could provide a mechanism for passing additional, dynamically instantiated, registries around.</strong></p>

        <p>Nope.  That just get's confusing.  A single registry is all you need.  Additional items could be passed using the registry.</p>

        <p>In my own code I just extended Zend_Controller_Action and have it store the current global $registry as an instance variable.  Not quite as nice as being able to directly inject a registry but it works ok.</p>

        <p>What I would really like to do is to get clarification about the registry itself.  Are we really going to be able to create Zend_Registry objects? Is Zend_Registry::getInstance()->name acceptable for accessing the registry?   </p>

        1. Jul 26, 2006

          <p>I think we can use the $arg "pass arguments by keyword" approach to satisfy almost everyone, and still achieve the original purpose of this proposal.</p>

          <p>The suggestion was to propose a patch that passes a single <strong>general-purpose</strong> parameter, say "args", that acts like a varargs, where additional parameters can be added to the $args hash table (i.e. PHP array used to pass arguments by keyword). Actions would then have access to this variable, and could optionally make use of a registry found inside the $args parameter.</p>

          <p>I believe this approach would win the favor of most, since it does not impact existing ZF users, yet makes it possible to use the registry for original purpose behind this proposal. The API is not "frozen". However, significant changes to the API and interaction between the router, controllers and actions raises concerns, unless that change is needed by most, or the change provides optional behavior not impacting current users. Adding $args would allow for other future extensions without changing the API directly (no additional code to core classes to add another <key,value> pair to $args).</p>

          <p>Applications using legacy code may have additional "registries" (collections of data/objects) they would like to make available to some actions, but not all (avoid the publish globally syndrome). Some may also wish to have dynamically scoped collections of objects. Again, the $args approach offers one possible solution.</p>

          <p>Yes, the "registry" code can live in Zend_Registry, but the original interface provided in Zend.php should remain in place, instead using an instantiated Zend_Registry. However, we need a mechanism for on-demand instantiation, and loading of the Zend_Registry class, with a way for developers to indicate which Zend_Registry class to use, if they subclassed Zend_Registry.</p>

          1. Jul 26, 2006

            <p>I think the idea of some sort of "args" value should be looked at and considered as a seperate item now.</p>

            <p>By having such a value already in use throughout the framework it will allow easier furture expansion of the framework.</p>

            <p>I can't imaging this registry proposal being the only proposal that will come up that would benifit from such a feature</p>

          2. Jul 27, 2006

            <p>Should $registry be passed to the constructor by itself or should it be passed as part of a general purpose indexed $args array? In other words:<br />
            $dispatch = new Dispatch($registry,$args)<br />
            OR<br />
            $dispatch = new Dispatch(array('registry' => $registry))</p>

            <p>$registry has a very specific use as a global accessor. It has also has a very specific requirement in that we expect an object to pass $registry along to certain additional objects that the object creates. For example, we expect the dispatcher to pass $registry onto the controller object.</p>

            <p>So the constructor has a very simple job to do as far as $registry is concerned. We expect the constructor to simply store $registry as an instance variable with a name of 'registry'. Clean and easy to understand. And it's not unreasonable to consider $registry as being more than just a regular argument.<br />
            —<br />
            The intent behind using $args is that additional arguments could then be included to support future functionality without changing the api. Thats great but what kind of standard behaviour do we expect from a constructor? We can't simply store $args as an instance variable and expect each individual method to extract their data from it. Rather, in most cases, a constructor will immediately pull apart $args and store the individual bits and pieces as instance data.</p>

            <p>But remember that somewhere in dispatch we will be creating a controller. So do we expect dispatch to pass the complete $args onto the controller? What if some of the sutff in $args was only meant for the dispatcher? And maybe some is only meant for the controller. And maybe some might even conflict between the two classes. You really need some code somewhere to explicitly decide what to do. Or only pass $registry along in which case we end up where we started.</p>

            <p>I suppose you could say that we will just handle $registry as a special case and always just pull it out based on a global key name but that really seems unneccessary to me. Seems like you will end up adding and retrieving $registry from arrays in many parts of the code with no real value being added. Treat $register and $args as different concepts. Let $args be for the current object and let $register be the global accessor.</p>

            <p>And if you do need to pass some additional arguments onto the controller then override the dispatch method and add them in. </p>

            <p>Also consider that, except for Zend_View, the major VC classes currently have empty constructors. Does not seem to be a huge need for additional arguments. And even the Zend_View arguments are optional. In fact few people probably even know they exist. So we won't be breaking existing application code except for the Zend_View constructor which few people are using.</p>

            <p>So my vote is: $dispatch = new Dispatch($registry,$args)</p>

      2. Jul 26, 2006

        <p>Gavin, can you show use some use case code on how you envision this to be implemented/work. I think I understand, but small differences can be big differences in areas like this. Thanks.</p>

  8. Jul 26, 2006

    <p>Working source code with units tests has been posted here:
    <a class="external-link" href="http://zayso.org/zendfw/index.html">http://zayso.org/zendfw/index.html</a></p>

    <p>Most of it was copied/pasted from the 0.1.5 preview code.</p>

    <p>The original static Zend: registry functions will now work with the Zend_Registry object.</p>

    <p>The novice user can also specify the registry class during startup while still using the static interface.</p>

    <p>Let's see if we can reach some kind of agreement in the implementation and then we can continue the fight on hot to pass it around.</p>

    <p>By the way, I really think the registry should be passed around by itself as the first argument in most constructors. If you really want a generic $args then pass it in the second spot. But I think the registry will eliminate the need for $args in most cases. But let's keep the concepts separate so the user does not need to keep building and unbuilding arrays.</p>

    1. Jul 26, 2006

      <p>Yes, the implementation looks like what I was expecting, except the foreach used to iterate over objects in the registry to avoid storing duplicates can be simplified by using in_array(). I checked the C source code for PHP, and in_array() does the "right" thing for objects <ac:emoticon ac:name="smile" /></p>

      <p>I'm pretty sure we can get this much approved by the team.</p>

      1. Jul 26, 2006

        <p>Are your sure about in_array()? I just tried it (as well as array_search would be better here) and it always seems to return true once an object has been stored. Can't store a second object at all. Might be doing something wrong. Glad to hear the code might be accepted. PHP 5.1.4</p>

        1. Aug 04, 2006

          <p>I have not been able to replicate the described problem.<br />
          Everything seems to work as expected:</p>
          <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
          <?
          $registry = array();

          class foo
          {
          public $iam;
          public function __construct($iam)

          Unknown macro: { $this->iam=$iam; }

          }

          function r($name, $obj)
          {
          global $registry;
          #foreach ($registry as $dup=>$registeredObject)

          1. if ($obj === $registeredObject) echo 'duplicate: ', $obj->iam, "\n";
            if (($key = array_search($obj, $registry)) !== FALSE)
            echo 'warning: duplicate key: ', $key, "\n";

          $registry[$name] = $obj;
          }

          $a = new foo('apple');
          $p = new foo('pear');
          $c = new foo('carrot');

          r('a',$a);
          r('p',$p);
          r('c',$c);
          r('c',$c);
          r('p',$p);
          r('cat',$c);
          r('pepper',$p);

          var_dump($registry);
          ]]></ac:plain-text-body></ac:macro>
          <p>This example permits duplicates, but warns.</p>

          1. Aug 10, 2006

            <p>Ok. Be aware that array_search will think that:</p>

            <p>$obj1 = new foo('apple');<br />
            $obj2 = new foo('apple');</p>

            <p>are the same object. Which I think is bogus but if that's they way Zend wants it then fine.</p>

            1. Aug 21, 2006

              <p>Use "true" for third, optional parameter for in_array().</p>

  9. Aug 07, 2006

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Feedback</ac:parameter><ac:rich-text-body>
    <p>This proposal is conditionally accepted, provided that all proposed changes to controller/action classes are made available as a patch attached to an issue in the issue tracker. The community can then review and comment on that patch, before a final decision is reached regarding passing an additional (optional) parameter to the controller.</p></ac:rich-text-body></ac:macro>

  10. Aug 23, 2006

    <p>Why not make the registry a Singleton?</p>

    <p>This would solve the need for passing on the registry to other classes.</p>

    <p>$registry = Zend_Registry::instance();</p>

    1. Aug 24, 2006

      <p>There already is the Zend class to provide static access to this functionality. This class is for programmers who prefer not to use a Singleton for reasons posted above. </p>

  11. Aug 25, 2006

    <p>I would like to suggest another idea to consider. If the register() function accepts flags to select from the behaviors below, then we significantly reduce the need for subclassing Zend_Registry:</p>
    <ul class="alternate">
    <li>flag to permit register($name, $obj) to overwrite the value associated with the key $name</li>
    <li>flag to permit entries having duplicate objects bug different key names</li>
    </ul>

    <p>Our primary concern with the above focuses on avoiding situations where code combined from different developers expecting incompatible behavior from the registry.</p>

  12. Sep 17, 2006

    <p>How about something like this? It allows you to get an object from the Registry that implements a specific interface or is of a certain class type. This would be useful for example with Zend_View_Helpers</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $request = $registry->getInstanceOf('Zend_Request_Http');
    $router = $registry->getInstanceOf('Zend_Controller_Router_Interface')
    return $request->basePath . $router->getCurrentRoute()->assemble('foo', 'bar');
    ]]></ac:plain-text-body></ac:macro>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    /**

    • Returns the first object in the Registry that
    • is an instance of $class. An exception is
    • thrown for objects not found.
      *
    • @param string $class
    • @return object
      */
      public function getInstanceOf($class)
      {
      foreach ($this->_registry as $name => $object)
      Unknown macro: { if ($object instanceof $class)
      Unknown macro: { return $object; }
      }

    throw new Zend_Registry_Exception("No object of type \"$name\" is registered.");
    }
    ]]></ac:plain-text-body></ac:macro>

    1. Sep 17, 2006

      <p>I have to stop coding when I'm tired <ac:emoticon ac:name="smile" /> My function had some bugs that are now fixed:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      /**

      • Returns the first object in the Registry that is an instance
      • of $type. An exception is thrown for objects not found.
        *
      • @param string $type
      • @return object
        */
        public function getInstanceOf($type)
        {
        foreach ($this->_registry as $obj)
        Unknown macro: { if ($obj instanceof $type)
        Unknown macro: { return $obj; }
        }

      throw new Zend_Registry_Exception("No object of type \"$type\" is registered.");
      }
      ]]></ac:plain-text-body></ac:macro>

  13. Oct 28, 2006

    <ac:macro ac:name="unmigrated-wiki-markup"><ac:plain-text-body><![CDATA[class Example
    {
    /**

    • registry.
      *
    • @var array
      */
      private static $_registry = array();

    public static function _registry($className)
    {
    if (false !== array_key_exists($className, self::$_registry))

    Unknown macro: { return self}

    else

    Unknown macro: { Zend}

    }

    }

    //
    /@var $ZendView Zend_View/
    $ZendView = Example::_registry('Zend_View');

    Your opinion ?

    ]]></ac:plain-text-body></ac:macro>

  14. Dec 18, 2006

    <p>The ZF's minimum supported PHP version now allows core components to use SPL. Per the ZF devteam's request the backend implementation shifted to using an ArrayObject, and the restrictions regarding (1) permitting only objects in the registry, (2) preventing removal of entries, and (3) disallowing duplicate values with different indexes, were removed.</p>

  15. Apr 04, 2007

    <p>Hello,</p>

    <p>I don't know if this was alrready considered, but a Registry class without an clearly defined interface is not a good idea in my opinion.</p>

    <p>Because after there has been defined such an interface not just one but many different registries for different purposes could be implemented.</p>

    <p>For example I would like to have a Session_Registry class rather than putting a session object into a "normal" registry.</p>

    <p>Both session and registry objects do the same thing, the just store objects... So they should implement the same interface.</p>

    <p>And there could even be a Persistent_Registry class that writes the data to the harddisk. (think of windows registry)</p>

    <p>And all of them would be exchangeable due to a clearly defined interface. </p>

    <p>At the moment I hate it to access data from a session object and registry object in different ways and not beeing able to exchange these objects.</p>

  16. Apr 04, 2007

    <p>Hello again,</p>

    <p>another idea for registry objects could be to implement the observer pattern. Then objects that have registered themselves with a registry object would be informed if for example an entry has been changed, deleted or added.</p>