我有一个使用 PDO 的数据库包装类,并在构造函数中创建一个 PDO 对象。包装类位于我们的命名空间中,我们正在使用自动加载器。问题是在我们的命名空间中找不到 PDO 类,因此我尝试使用全局命名空间,如此处所述。
//Class file
namespace Company\Common;
class DB {
private function __construct(){
$this->Handle=new PDO(...);
}
}
有了这个,我得到了这个(如预期的那样):
Warning: require(...\vendors\Company\Common\PDO.class.php): failed to open stream
如果我这样做:
namespace Company\Common;
use PDO;
我明白了:
Fatal error: Class 'DB' not found in ...\includes\utils.php
utils.php 在错误行中包含此内容,在实现名称空间之前工作正常:
DB::getInstance();
或者我尝试了这个:
namespace Company\Common;
class DB {
private function __construct(){
$this->Handle=new \PDO(...);
}
}
它尝试像最初一样在我们的命名空间中加载 PDO 类。
我该如何解决这个问题?我以为通过执行
use PDO
或 new \PDO
可以加载全局 PDO 类,但它似乎不起作用?
在命名空间 PHP 中,对类的引用必须包含该类的命名空间,除非您有包含该类或其命名空间的一部分的
use
语句。
因此,如果您没有
use
语句,则必须使用前导反斜杠引用 PDO 和其他全局类 - 即 $obj = new \PDO();
如果您有一个引用该类的
use
语句,那么您可以仅通过类名来引用它:
use PDO;
....
$obj = new PDO();
如果您引用了很多全局类,并且想避免每次都使用反斜杠,则需要单独使用
use
。
通常在我们的项目中,我们确实设置这样的包含路径:
set_include_path('PATH_TO_GLOBAL_LIBS; PATH_TO_LIBRARY_1; PATH_TO_LIBRARY_X; PATH_TO_DOCUMENT_ROOT');
通过此,我们告诉 PHP (Apache) 在这些路径中搜索自动加载器应包含的任何类。
然后假设我们在
Library_1
中有一些 /var/www/Libs/library_1
并且该路径被添加到 include_path 中,我们可以这样做:
namespace Company\Common;
Class DB {
private function __construct() {
$this->Handle = new \Library_1();
}
}
应该与
相同namespace Company\Common;
use \Library_1;
Class DB {
private function __construct() {
$this->Handle = new Library_1();
}
}
这行得通,你的问题在别的地方。
index.php
<?php
include('_db.php');
use Company\Common\DB;
new DB;
_db.php
<?php
namespace Company\Common;
use \PDO;
class DB {
public function __construct() {
$this->Handle = new PDO;
}
}
要访问像
PDO
和 DateTime
这样的全局对象,您需要在它们前面加上反斜杠。所以你有两个选择。
首先,
use
您希望在名称空间类文件中使用的类:
<?php
namespace Vendor;
use \PDO;
use \PDOException;
class MyClass
{
public function __construct()
{
try {
$db = new PDO($dsn, $user, $pass);
$db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e) {
echo $e->getMessage();
exit;
}
}
}
或者只在类中使用反斜杠前缀的声明:
<?php
namespace Vendor;
class MyClass
{
public function __construct()
{
try {
$db = new \PDO($dsn, $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (\PDOException $e) {
echo $e->getMessage();
exit;
}
}
}
就我个人而言,我更喜欢第一种方法。
解决了。我没有意识到命名空间别名仅适用于当前文件,而不适用于任何未来包含的文件。在 PHP.net 上找到了这个,它也适用于别名:
导入规则是基于每个文件的,这意味着包含的文件不会继承父文件的导入规则。
附录:使用全局命名空间中的类作为函数类型提示,似乎需要“使用