【问题标题】:using php namespaces correctly正确使用 php 命名空间
【发布时间】:2013-01-31 02:17:45
【问题描述】:

我刚刚开始重建我使用命名空间制作的应用程序,以使未来的开发更容易,因此我们可以重用类名。

基本上我的代码如下。

<?php
session_start();

error_reporting(E_ALL);
ini_set('display_errors', 1);

use core\marketing as marketing;
use core\security as security;
use core\structure as structure;
use core\data as data;

include 'marketing\cleanurl.php';
?>

一旦我运行它,我就会收到以下错误:

警告:include(marketing\cleanurl.php):无法打开流:第 27 行的 /var/www/index.php 中没有这样的文件或目录警告:include():打开 'marketing\cleanurl.php 失败' 在第 27 行的 /var/www/index.php 中包含 (include_path='.:/usr/share/php:/usr/share/pear')

我的目录结构与命名空间相匹配,因为这是我在网上看到的。

现在,如果我更改包含以匹配目录,即

include 'core/marketing/cleanurl.php';

我收到以下错误

解析错误:语法错误,意外的 T_CLASS,需要 T_NS_SEPARATOR 或 ';'或第 4 行 /var/www/twiggled/core/marketing/cleanurl.php 中的“{”

当我只是使用 require_once 来调用所有类时,这一切都奏效了,但发现系统的这种有限扩展并使更改更加耗时,并且想要使用命名空间,因为它们在我使用的其他语言中一直很棒。

【问题讨论】:

  • 你能发布cleanurl.php的内容吗
  • 第一个错误是当您将命名空间分隔符设计为看起来像来自错误平台的路径分隔符时发生的情况。 (您在需要正斜杠的 Unix 文件系统上,但使用了 Windows 反斜杠。)
  • @mario 根据 PHP 文档,命名空间分隔符是正确的。问题似乎与您如何包含 cleanurl 文件有关。这似乎是斜线可能是问题所在。如果您使用的是 unix 系统,请更改为“marketing/cleanurl.php”,并确保您没有在某处省略分号。
  • 命名空间和文件路径是完全分开的,它们不能一起工作。第一个错误是文件路径错误的常规问题。第二个是正常的语法错误,我们必须查看它出现的文件。
  • 您的cleanurl.php 可能在namespace core\marketing 声明之后缺少一个分号。

标签: php namespaces


【解决方案1】:

由于 OP 要求它,这是使用自动加载的更新答案。

注意:为了简化任务,当然不需要如此复杂的结构。然而,这只是一个例子如何协同工作(自动加载、要求、静态方法等)。

引导/自动加载

/var/www/somedir/Twiggled/bootstrap.php

<?php
namespace Twiggled;

require_once __DIR__ . '\Common\AutoLoader.php';

$autoloader = new \Twiggled\Common\AutoLoader(__NAMESPACE__, dirname(__DIR__));
$autoloader->register();

/var/www/somedir/Twiggled/Common/AutoLoader.php

<?php
namespace Twiggled\Common;

/**
 * PSR-0 Autoloader
 *
 * @package    Common
 */
class AutoLoader
{
    /**
     * @var string The namespace prefix for this instance.
     */
    protected $namespace = '';

    /**
     * @var string The filesystem prefix to use for this instance
     */
    protected $path = '';

    /**
     * Build the instance of the autoloader
     *
     * @param string $namespace The prefixed namespace this instance will load
     * @param string $path The filesystem path to the root of the namespace
     */
    public function __construct($namespace, $path)
    {
        $this->namespace = ltrim($namespace, '\\');
        $this->path      = rtrim($path, '/\\') . DIRECTORY_SEPARATOR;
    }

    /**
     * Try to load a class
     *
     * @param string $class The class name to load
     *
     * @return boolean If the loading was successful
     */
    public function load($class)
    {
        $class = ltrim($class, '\\');

        if (strpos($class, $this->namespace) === 0) {
            $nsparts   = explode('\\', $class);
            $class     = array_pop($nsparts);
            $nsparts[] = '';
            $path      = $this->path . implode(DIRECTORY_SEPARATOR, $nsparts);
            $path     .= str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';

            if (file_exists($path)) {
                require $path;
                return true;
            }
        }
        return false;
    }

    /**
     * Register the autoloader to PHP
     *
     * @return boolean The status of the registration
     */
    public function register()
    {
        return spl_autoload_register(array($this, 'load'));
    }

    /**
     * Unregister the autoloader to PHP
     *
     * @return boolean The status of the unregistration
     */
    public function unregister()
    {
        return spl_autoload_unregister(array($this, 'load'));
    }
}

包文件

/var/www/somedir/Twiggled/Core/Helper/Strings.php

<?php
namespace Twiggled\Core\Helper;

class Strings
{
    // Note: Eventhough the method use a global PHP function name,
    // there is no problem with it - thanks to namespace.
    public static function str_replace($str) 
    {
        $str = preg_replace('/\s/', '_', strtolower($str));
        return preg_replace('/[^a-zA-Z_]/', '', $str);
    }
}

/var/www/somedir/Twiggled/Core/Marketing/Cleanurl.php

<?php
namespace Twiggled\Core\Marketing;

use \Twiggled\Core\Helper\Strings as HelperStrings;

class Cleanurl 
{
    const BASE_URL = 'http://example.com/';
    public $cleanPath;

    public function __construct($str) 
    {
        $this->cleanPath= HelperStrings::str_replace($str);
    }
}

加载并使用它..

/var/www/somedir/index.php

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('date.timezone', 'Europe/Berlin');

// Bootstrap the package / register autoloader
require_once __DIR__ . '\Twiggled\bootstrap.php';

use \Twiggled\Core\Marketing as Marketing;

try {
    $obj = new Marketing\Cleanurl('$This w-ork5s!');

    // prints 'http://example.com/this_works'.
    echo Marketing\Cleanurl::BASE_URL . $obj->cleanPath; 
} 
catch (\Exception $e) { }

【讨论】:

  • 谢谢,但如果我不得不使用 require ,那么使用命名空间毫无意义,曾经试图从这种方式转移到命名空间以获得更好的架构。尽管使用 PHP 似乎不可能。哦,好吧。
  • 我不明白你的意思?! 1.) 请注意,这是基于您提供的信息的简化示例。但即使您使用自动加载器(我强烈推荐),您仍然需要包含自动加载器(即需要它)。 2.) 请记住,命名空间的一个要点是避免您自己的代码与内部 PHP 和/或第三方类/函数/常量之间的名称冲突。本质上,PHP 中的命名空间只不过是一个分层标记的代码块,其中包含常规 PHP 代码。因此,即使您不使用自动加载器而是使用包含,命名空间仍然可以避免名称冲突。
  • 我使用的是自动加载器,看起来像这样,它似乎正确 function _autoload($className) { $filename = str_replace('\\', '/' , $className) 。 'php' ;需要一次$文件名; }
  • @Paul 查看我更新的答案,了解使用自动加载的示例。
  • 感谢您在重新观看教程并使用您的示例重新阅读所有内容后的帮助,我现在明白了。这个周末会试一试,看看进展如何。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-27
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
  • 2012-05-19
  • 2017-07-18
相关资源
最近更新 更多