Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Namespace auto-aliasing. #3

Open
alganet opened this issue Apr 14, 2012 · 3 comments
Open

Namespace auto-aliasing. #3

alganet opened this issue Apr 14, 2012 · 3 comments
Labels
Milestone

Comments

@alganet
Copy link
Member

alganet commented Apr 14, 2012

Respect projects are often designed to be extensible trough a namespace.

Respect\Validation has Respect\Validation\Rules and Respect\Validation\Exception namespaces that maps directly to the magic builders. This means that Respect\Validation\Validator::foo() builds an instance of Respect\Validation\Rules\Foo.

A trivial way of pluggin-in new rules on Validation is to create your own rule in your own namespace then importing it to the Respect namespace using class_alias. Sample:

class_alias('MyLib\Rules\Foo, 'Respect\Validation\Rules\Foo');`

When a library provides more than one rule, several calls to class_alias must be done.

Since Respect\Loader is responsible for loading classes, it could include a namespace aliasing feature. Usage would be something like:

Respect\Loader::namespaceAlias('MyLib\Rules', 'Respect\Validation\Rules');

This would make the class_aliases lazy by declaring them only on the autoload phase.

Other libraries and frameworks could take advantage of this as well, since several of them uses similar namespace re-usability.

@nickl-
Copy link
Member

nickl- commented Aug 2, 2012

O I see... said the blind man.

Even more lazy then can be, only consider aliases when all else fails, right? Add that to a healthy dose of caching and the solution can be simple recursion without extra overhead, you see:

<?php

        public function __invoke($classname) {
             if ($seen_before)
                   return $from_cache[$classname];

              /** here we find our fully qualified names */
              /** we cache these, won't go through all that again */

              /** can't find this one but lets not give up just yet */

              foreach (static::$namespaceAliases as $alias)
                    if (null !== $lazy = $this->__invoke("$alias$classname");
                       return $lazy; // but also cache it first!

              /** ok I give up, this guy really doesn't exist ok. lets cache this too */
              /** result will stay the same, even when doing that all over again */ 
        }

Any concerns I may have missed?

@alganet
Copy link
Member Author

alganet commented Aug 6, 2012

Awesome snack, I'm a happy panda! I haven't thought of these ones together =D

@nickl-
Copy link
Member

nickl- commented Aug 8, 2012

Closer to the truth and a tad less pseudo:

<?php

    /**
     * Autoloader callback through __invoke object as function.
     *
     * @param $className string class name to auto load
     * @return mixed|null the reference from the include or null
     */
    public function __invoke($className)
    {
        if (false !== $includeReference = $this->discover($className))
            return $includeReference;

        if (false !== $includeReference = $this->loadAliases($className))
            return $includeReference;

        if (false !== $includeReference = $this->loadPrefixes($className))
            return $includeReference;

        $this->seen($className, true);
    }

    private function loadPrefixes($className)
    {
        for ($i        = 0
            ,$file     = false
            ,$count    = count(static::$aliases)
            ,$prefixes = array_keys(static::$aliases)
            ;$i        < $count
            && false === $file
            && false === $file = $this->discover(
                      $variant = "{$prefixes[$i++]}\\$className",
                      $className)
            ;$file = $this->loadAliases($variant)
        );
        return $file;
    }

    private function loadAliases($className)
    {
        $file     = false;
        if (preg_match('/(.+)(\\\\\w+$)/U', $className, $parts))
                for ($i        = 0
                    ,$aliases  = @static::$aliases[$parts[1]] ?: array()
                    ,$count    = count($aliases)
                    ;$i        < $count
                    && false === $file
                    ;$file     = $this->discover(
                                    "{$aliases[$i++]}$parts[2]",
                                     $className
                                  )
                );
        return $file;
    }

    private function discover($className, $currentClass=null)
    {
        $currentClass = $currentClass ?: $className;
        if (false !== $file = $this->seen($className)) {
            if (!$this->exists($className))
                $file = $this->loadFile($file);

   //... ... ... ... ... ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants