2011/02/06

PSR-0

日本語訳(下書き):
PSR-0 Final Proposal - PHP Standards Working Group - 2009-11-14
http://groups.google.com/group/php-standards/web/psr-0-final-proposal

PSR-0 最終提案

オートローダーの相互運用性に関する遵守すべき必須条件を以下に記載します。

必須項目

  1. 完全修飾形式の名前空間つきのクラスには、次のような構造を持たせること。
    \<Vendor Name>\(<Namespace>\)*<Class Name>
    (訳注:「\ベンダー名\名前空間\クラス名」が基本になります。)
  2. 名前空間には、トップレベルの名前空間 (「ベンダー名」) を必ず持たせること。
    (訳注:「\<Vendor Name>\(<Namespace>\)*」の「\<Vendor Name>\」部分です。)
  3. 名前空間は、サブ名前空間を好きなだけ持つことができます。
    (訳注:「\<Vendor Name>\(<Namespace>\)*」の「(<Namespace>\)*」部分です。)
  4. ファイルシステムからロードする際、名前空間の区切り文字は DIRECTORY_SEPARATOR に変換されます。
    (訳注:「\」マークを PHP の定義済み定数 DIRECTORY_SEPARATOR に置換します。)
  5. クラス名に含まれる「_」文字は、DIRECTORY_SEPARATOR に変換されます。名前空間に含まれる「_」文字は特別な意味を持ちません。
    (訳注: クラス名に対してのみ「_」文字を DIRECTORY_SEPARATOR に置換します。)
  6. ファイルシステムからロードする際、完全修飾形式の名前空間つきのクラスの接頭辞に「.php」がつけられます。
  7. ベンダー名や名前空間、およびクラス名に含まれる英字は、大文字や小文字の組み合わせでも構いません。

  • \Doctrine\Common\IsolatedClassLoader =>
    /path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php
    // Linux の場合は (4) が適用され、「\」から「/」に置換されます。
    // (6) が適用され、名前空間とクラスからなる文字列の最後に「.php」が付加されます。
    
  • \Symfony\Core\Request =>
    /path/to/project/lib/vendor/Symfony/Core/Request.php
    
  • \Zend\Acl =>
    /path/to/project/lib/vendor/Zend/Acl.php
    
  • \Zend\Mail\Message =>
    /path/to/project/lib/vendor/Zend/Mail/Message.php
    

名前空間およびクラス名におけるアンダースコア

  • \namespace\package\Class_Name =>
    /path/to/project/lib/vendor/namespace/package/Class/Name.php
    // クラス名 (ここでは Class_Name) は (5) が適用され、「_」部分が置換されます。
    
  • \namespace\package_name\Class_Name =>
    /path/to/project/lib/vendor/namespace/package_name/Class/Name.php
    // 名前空間 (ここでは package_name) では、「_」に対して何も行いません。
    

ここで定めた基準は、オートローダーの相互運用性に苦労しないための最低限の共通項目になります。 PHP 5.3 のクラスをロードすることのできる実装例 SplClassLoader を利用することで、ここで規定した規格に準拠しているかどうかをテストすることができます。

実装例

上述の提案規格に従ったオートロードの仕方について、簡単にデモする関数の例を次に示します。

<?php

function autoload($className)
{
    $className = ltrim($className, '\\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strripos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
}

SplClassLoader の実装

以下の gist は、SplClassLoader の実装例になります。 これは、前述のオートローダーの相互運用性に関する提案規格に沿ったクラスをロードすることができます。 また、その規格に沿った PHP 5.3 クラスをロードするのに現在推奨されている方法になります。

http://gist.github.com/221634
SplClassLoader.php - 2009-11-11

<?php

/**
 * SplClassLoader の実装.
 * PHP5.3 の名前空間およびクラス名に関する相互運用性の技術基準を実装しています.
 *
 * http://groups.google.com/group/php-standards/web/final-proposal
 *
 *     // Doctrine\Common 名前空間が含まれる
 *     // Doctrine 共通パッケージのクラスをロードする例.
 *     $classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine');
 *     $classLoader->register();
 *
 * @author Jonathan H. Wage <jonwage gmail.com>
 * @author Roman S. Borschel <roman code-factory.org>
 * @author Matthew Weier O'Phinney <matthew zend.com>
 * @author Kris Wallsmith <kris.wallsmith gmail.com>
 * @author Fabien Potencier <fabien.potencier symfony-project.org>
 */
class SplClassLoader
{
    private $_fileExtension = '.php';
    private $_namespace;
    private $_includePath;
    private $_namespaceSeparator = '\\';

    /**
     * 指定された名前空間に属するクラスをロードする
     * <tt>SplClassLoader</tt> を生成する.
     *
     * @param string $ns 使用する名前空間
     * @param string $includePath ベースとなるインクルードパス
     */
    public function __construct($ns = null, $includePath = null)
    {
        $this->_namespace = $ns;
        $this->_includePath = $includePath;
    }

    /**
     * 本クラスローダーの名前空間に属するクラスに使用される名前空間の区切り文字を設定する.
     *
     * @param string $sep 使用する区切り文字
     */
    public function setNamespaceSeparator($sep)
    {
        $this->_namespaceSeparator = $sep;
    }

    /**
     * 本クラスローダーの名前空間に属するクラスに使用される名前空間の区切り文字を取得する.
     *
     * @return string
     */
    public function getNamespaceSeparator()
    {
        return $this->_namespaceSeparator;
    }

    /**
     * 本クラスローダーの名前空間に属するすべてのクラスファイルのベースとなるインクルードパスを設定する.
     *
     * @param string $includePath
     */
    public function setIncludePath($includePath)
    {
        $this->_includePath = $includePath;
    }

    /**
     * 本クラスローダーの名前空間に属するすべてのクラスファイルのベースとなるインクルードパスを取得する.
     *
     * @return string
     */
    public function getIncludePath()
    {
        return $this->_includePath;
    }

    /**
     * 本クラスローダーの名前空間に属するクラスファイルの拡張子を設定する.
     *
     * @param string $fileExtension
     */
    public function setFileExtension($fileExtension)
    {
        $this->_fileExtension = $fileExtension;
    }

    /**
     * 本クラスローダーの名前空間に属するクラスファイルの拡張子を取得する.
     *
     * @return string
     */
    public function getFileExtension()
    {
        return $this->_fileExtension;
    }

    /**
     * SPL の autoload スタックに本クラスローダーをインストールする.
     */
    public function register()
    {
        spl_autoload_register(array($this, 'loadClass'));
    }

    /**
     * SPL の autoload スタックから本クラスローダーをアンインストールする.
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));
    }

    /**
     * クラスまたはインタフェースをロードする.
     *
     * @param string $className ロードするクラス名
     * @return void
     */
    public function loadClass($className)
    {
        if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) {
            $fileName = '';
            $namespace = '';
            if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) {
                $namespace = substr($className, 0, $lastNsPos);
                $className = substr($className, $lastNsPos + 1);
                $fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
            }
            $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension;

            require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName;
        }
    }
}

別訳:
PSR-0 を和訳してみた - hnwの日記
http://d.hatena.ne.jp/hnw/20101006

0 コメント: