소스 검색

Merge remote branch 'dustinwhittle/master'

* dustinwhittle/master:
  [Classloader] Added phpdoc with example usage + refactored unit tests fixtures
  [Classloader] Refactored ApcUniversalClassLoader to use setUp() to detect APC
  [Classloader] Fixed typo + coding standards in ApcUniversalClassLoader test
  [Classloader] Fixed APC class loader + added unit tests
Fabien Potencier 14 년 전
부모
커밋
36a63be0a5
19개의 변경된 파일362개의 추가작업 그리고 3개의 파일을 삭제
  1. 50 3
      src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php
  2. 192 0
      tests/Symfony/Tests/Component/ClassLoader/ApcUniversalClassLoaderTest.php
  3. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/Bar.php
  4. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/Baz.php
  5. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/Foo.php
  6. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/FooBar.php
  7. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Pearlike/Bar.php
  8. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Pearlike/Baz.php
  9. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Pearlike/Foo.php
  10. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Bar.php
  11. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Foo.php
  12. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/NamespaceCollision/A/Bar.php
  13. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/NamespaceCollision/A/Foo.php
  14. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Bar.php
  15. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Foo.php
  16. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/NamespaceCollision/A/B/Bar.php
  17. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/NamespaceCollision/A/B/Foo.php
  18. 6 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/fallback/Apc/Pearlike/FooBar.php
  19. 8 0
      tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/fallback/Namespaced/FooBar.php

+ 50 - 3
src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php

@@ -11,11 +11,51 @@
 
 namespace Symfony\Component\ClassLoader;
 
-require_once __DIR__.'/UniversalClassLoader.php';
-
 /**
- * Class loader utilizing APC to remember where files are.
+ * ApcUniversalClassLoader implements a "universal" autoloader cached in APC for PHP 5.3.
+ *
+ * It is able to load classes that use either:
+ *
+ *  * The technical interoperability standards for PHP 5.3 namespaces and
+ *    class names (http://groups.google.com/group/php-standards/web/psr-0-final-proposal);
+ *
+ *  * The PEAR naming convention for classes (http://pear.php.net/).
+ *
+ * Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
+ * looked for in a list of locations to ease the vendoring of a sub-set of
+ * classes for large projects.
+ *
+ * Example usage:
+ *
+ *     require 'vendor/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
+ *     require 'vendor/symfony/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php';
+ *
+ *     use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
+ *
+ *     $loader = new ApcUniversalClassLoader('apc.prefix.');
  *
+ *     // register classes with namespaces
+ *     $loader->registerNamespaces(array(
+ *         'Symfony\Component' => __DIR__.'/component',
+ *         'Symfony'           => __DIR__.'/framework',
+ *         'Sensio'            => array(__DIR__.'/src', __DIR__.'/vendor'),
+ *     ));
+ *
+ *     // register a library using the PEAR naming convention
+ *     $loader->registerPrefixes(array(
+ *         'Swift_' => __DIR__.'/Swift',
+ *     ));
+ *
+ *     // activate the autoloader
+ *     $loader->register();
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
  * @author Kris Wallsmith <kris.wallsmith@symfony.com>
  *
  * @api
@@ -36,6 +76,13 @@ class ApcUniversalClassLoader extends UniversalClassLoader
         $this->prefix = $prefix;
     }
 
+    /**
+     * Finds a file by class name while caching lookups to APC.
+     *
+     * @param string $class A class name to resolve to file
+     *
+     * @api
+     */
     public function findFile($class)
     {
         if (false === $file = apc_fetch($this->prefix.$class)) {

+ 192 - 0
tests/Symfony/Tests/Component/ClassLoader/ApcUniversalClassLoaderTest.php

@@ -0,0 +1,192 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\ClassLoader;
+
+use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
+
+class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
+{
+
+    protected function setUp()
+    {
+        if (!extension_loaded('apc')) {
+            $this->markTestSkipped('The apc extension is not available.');
+        }
+
+        if (!(ini_get('apc.enabled') && ini_get('apc.enable_cli'))) {
+            $this->markTestSkipped('The apc extension is available, but not enabled.');
+        }
+
+        apc_clear_cache('user');
+    }
+
+	protected function tearDown()
+	{
+        apc_clear_cache('user');
+	}
+
+    public function testConstructor()
+    {
+        $loader = new ApcUniversalClassLoader('test.prefix.');
+        $loader->registerNamespace('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
+
+        $this->assertEquals($loader->findFile('\Apc\Namespaced\FooBar'), apc_fetch('test.prefix.\Apc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument');
+    }
+
+   /**
+    * @dataProvider getLoadClassTests
+    */
+   public function testLoadClass($className, $testClassName, $message)
+   {
+       $loader = new ApcUniversalClassLoader('test.prefix.');
+       $loader->registerNamespace('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
+       $loader->registerPrefix('Apc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
+       $loader->loadClass($testClassName);
+       $this->assertTrue(class_exists($className), $message);
+   }
+
+   public function getLoadClassTests()
+   {
+       return array(
+           array('\\Apc\\Namespaced\\Foo', '\\Apc\\Namespaced\\Foo',   '->loadClass() loads Apc\Namespaced\Foo class'),
+           array('Apc_Pearlike_Foo',    'Apc_Pearlike_Foo',      '->loadClass() loads Apc_Pearlike_Foo class'),
+           array('\\Apc\\Namespaced\\Bar', '\\Apc\\Namespaced\\Bar', '->loadClass() loads Apc\Namespaced\Bar class with a leading slash'),
+           array('Apc_Pearlike_Bar',    '\\Apc_Pearlike_Bar',    '->loadClass() loads Apc_Pearlike_Bar class with a leading slash'),
+       );
+   }
+
+   /**
+    * @dataProvider getLoadClassFromFallbackTests
+    */
+   public function testLoadClassFromFallback($className, $testClassName, $message)
+   {
+       $loader = new ApcUniversalClassLoader('test.prefix.fallback');
+       $loader->registerNamespace('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
+       $loader->registerPrefix('Apc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
+       $loader->registerNamespaceFallback(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/fallback');
+       $loader->registerPrefixFallback(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/fallback');
+       $loader->loadClass($testClassName);
+       $this->assertTrue(class_exists($className), $message);
+   }
+
+   public function getLoadClassFromFallbackTests()
+   {
+       return array(
+           array('\\Apc\\Namespaced\\Baz',    '\\Apc\\Namespaced\\Baz',    '->loadClass() loads Apc\Namespaced\Baz class'),
+           array('Apc_Pearlike_Baz',       'Apc_Pearlike_Baz',       '->loadClass() loads Apc_Pearlike_Baz class'),
+           array('\\Apc\\Namespaced\\FooBar', '\\Apc\\Namespaced\\FooBar', '->loadClass() loads Apc\Namespaced\Baz class from fallback dir'),
+           array('Apc_Pearlike_FooBar',    'Apc_Pearlike_FooBar',    '->loadClass() loads Apc_Pearlike_Baz class from fallback dir'),
+       );
+   }
+
+   /**
+    * @dataProvider getLoadClassNamespaceCollisionTests
+    */
+   public function testLoadClassNamespaceCollision($namespaces, $className, $message)
+   {
+       $loader = new ApcUniversalClassLoader('test.prefix.collision.');
+       $loader->registerNamespaces($namespaces);
+
+       $loader->loadClass($className);
+
+       $this->assertTrue(class_exists($className), $message);
+   }
+
+   public function getLoadClassNamespaceCollisionTests()
+   {
+       return array(
+           array(
+               array(
+                   'Apc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+               ),
+               '\Apc\NamespaceCollision\A\Foo',
+               '->loadClass() loads NamespaceCollision\A\Foo from alpha.',
+           ),
+           array(
+               array(
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+                   'Apc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+               ),
+               '\Apc\NamespaceCollision\A\Bar',
+               '->loadClass() loads NamespaceCollision\A\Bar from alpha.',
+           ),
+           array(
+               array(
+                   'Apc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+               ),
+               '\Apc\NamespaceCollision\A\B\Foo',
+               '->loadClass() loads NamespaceCollision\A\B\Foo from beta.',
+           ),
+           array(
+               array(
+                   'Apc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta',
+                   'Apc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha',
+               ),
+               '\Apc\NamespaceCollision\A\B\Bar',
+               '->loadClass() loads NamespaceCollision\A\B\Bar from beta.',
+           ),
+       );
+   }
+
+   /**
+    * @dataProvider getLoadClassPrefixCollisionTests
+    */
+   public function testLoadClassPrefixCollision($prefixes, $className, $message)
+   {
+       $loader = new ApcUniversalClassLoader('test.prefix.collision.');
+       $loader->registerPrefixes($prefixes);
+
+       $loader->loadClass($className);
+       $this->assertTrue(class_exists($className), $message);
+   }
+
+   public function getLoadClassPrefixCollisionTests()
+   {
+       return array(
+           array(
+               array(
+                   'ApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+                   'ApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+               ),
+               'ApcPrefixCollision_A_Foo',
+               '->loadClass() loads ApcPrefixCollision_A_Foo from alpha.',
+           ),
+           array(
+               array(
+                   'ApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+                   'ApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+               ),
+               'ApcPrefixCollision_A_Bar',
+               '->loadClass() loads ApcPrefixCollision_A_Bar from alpha.',
+           ),
+           array(
+               array(
+                   'ApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+                   'ApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+               ),
+               'ApcPrefixCollision_A_B_Foo',
+               '->loadClass() loads ApcPrefixCollision_A_B_Foo from beta.',
+           ),
+           array(
+               array(
+                   'ApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/beta/Apc',
+                   'ApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc',
+               ),
+               'ApcPrefixCollision_A_B_Bar',
+               '->loadClass() loads ApcPrefixCollision_A_B_Bar from beta.',
+           ),
+       );
+   }
+
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/Bar.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\Namespaced;
+
+class Bar
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/Baz.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\Namespaced;
+
+class Baz
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/Foo.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\Namespaced;
+
+class Foo
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Namespaced/FooBar.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\Namespaced;
+
+class FooBar
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Pearlike/Bar.php

@@ -0,0 +1,6 @@
+<?php
+
+class Apc_Pearlike_Bar
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Pearlike/Baz.php

@@ -0,0 +1,6 @@
+<?php
+
+class Apc_Pearlike_Baz
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/Pearlike/Foo.php

@@ -0,0 +1,6 @@
+<?php
+
+class Apc_Pearlike_Foo
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Bar.php

@@ -0,0 +1,6 @@
+<?php
+
+class ApcPrefixCollision_A_Bar
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/ApcPrefixCollision/A/Foo.php

@@ -0,0 +1,6 @@
+<?php
+
+class ApcPrefixCollision_A_Foo
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/NamespaceCollision/A/Bar.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\NamespaceCollision\A;
+
+class Bar
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/alpha/Apc/NamespaceCollision/A/Foo.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\NamespaceCollision\A;
+
+class Foo
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Bar.php

@@ -0,0 +1,6 @@
+<?php
+
+class ApcPrefixCollision_A_B_Bar
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Foo.php

@@ -0,0 +1,6 @@
+<?php
+
+class ApcPrefixCollision_A_B_Foo
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/NamespaceCollision/A/B/Bar.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\NamespaceCollision\A\B;
+
+class Bar
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/beta/Apc/NamespaceCollision/A/B/Foo.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\NamespaceCollision\A\B;
+
+class Foo
+{
+    public static $loaded = true;
+}

+ 6 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/fallback/Apc/Pearlike/FooBar.php

@@ -0,0 +1,6 @@
+<?php
+
+class Apc_Pearlike_FooBar
+{
+    public static $loaded = true;
+}

+ 8 - 0
tests/Symfony/Tests/Component/ClassLoader/Fixtures/Apc/fallback/Namespaced/FooBar.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Apc\Namespaced;
+
+class FooBar
+{
+    public static $loaded = true;
+}