我尝试学习oop但是在我的第一堂课中它给了我这个错误。
数据库类
<?php
namespace App;
class Database
{
...
}
在我的functions.php
中<?php
require 'helpers.php';
require 'connection.php';
use App\Database;
...
“app”文件夹下的类,它的命名空间是“App”。为什么我收到此错误?
答案 0 :(得分:0)
您需要包含该文件,或使用AutoLoader。 AutoLoaders告诉PHP哪里可以找到一个类,因为PHP需要知道该文件。
自动加载器在PHP文档中有完整的解释: https://secure.php.net/manual/en/language.oop5.autoload.php
上述文件中的例子:
<?php
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
在这种情况下,spl_autoload_register用于注册自动加载器。自动加载器是一个获取类名的函数,并包含必要的类。例如,您可以使用上面使用的自动加载器功能,在这种情况下,类名称必须与文件名相同。 这是一个非常简单的示例,但更高级的自动加载器可以检查文件是否存在,检查多个位置等...
原始问题的comments中提到了示例。
注意:您会发现其他来源提及__autoload($ class)函数。此函数完全相同,但will be removed from PHP in future updates。因此,最好使用spl_autoload_register
答案 1 :(得分:0)
因为我在评论中发布了自动加载器。
https://github.com/ArtisticPhoenix/MISC/blob/master/Autoloader.php
您可以在此帖子的底部找到代码:
基本用法如下:
require_once 'Autoloader.php';
AutoLoader::getInstance()->regesterPath('\\', __DIR__);
这假设它位于作为命名空间根目录的目录中。所以,如果你有一个班级。
namespace App;
class Database{ ... }
此课程在
www
|- Autoloader.php
|- App
| --Database.php
然后它会查找__DIR__
+名称空间或__DIR__/APP/
。您可以注册路径,因为如果您有此设置。
www
|- Autoloader.php
|- includes
|-- App
| ---Database.php
如果课程位于includes/App
且Autoloader位于/
根文件夹中,您可以这样做。
require_once 'Autoloader.php';
AutoLoader::getInstance()->regesterPath('\\', __DIR__.'/includes/');
如果你有这样的设置。
www
|- Autoloader.php
|- includes
| --Database.php
如果没有实际的App
文件夹,那么你就可以这样做。
require_once 'Autoloader.php';
AutoLoader::getInstance()->regesterPath('\\App\\', __DIR__.'/includes/');
或上述的任何组合。
它将解释\\App
之间的差异。大部分时间App
和\\App\\
。但你也可以用这个开启调试。
require_once 'Autoloader.php';
$AutoLoader = AutoLoader::getInstance();
$AutoLoader->setDebug(true);
$AutoLoader>regesterPath('\\App\\', __DIR__.'/includes/');
它会吐出一堆东西告诉你它在哪里。如果您使用HTML,则可能必须使用<pre>
来保留空白格式。方便的是,您也可以关闭调试,因为您可能会自动加载一堆类。
$AutoLoader->setDebug(false);
您还可以分配多个路径,并为它们提供优先级,并按优先级顺序查看它们。但在这种情况下,这并不重要。
例如:
我有一个文件夹
www
|-MISC
|--index.php
|--Autoloader.php
|---IMAP
|----GmailClient.php
哪个也在同一个Git Repo中。它的名称空间为Lib\Email\IMAP
,其中只存在IMAP
。
并且如果我在index.php中执行此操作,该文件位于MISC
文件内且与AutoLoader.php
文件处于同一级别:
//include the Autoloader
require_once __DIR__.'/Autoloader.php';
//get an instance of it (Singleton pattern)
$Autoloader = Autoloader::getInstance();
//regester a namespace, path pair
$Autoloader->regesterPath('Lib\Email', __DIR__.'/IMAP/');
//preserve whitespace
echo "<pre>";
//turn on debugging before a problem class
$Autoloader->setDebug(true);
//Attempt to load the class as normal
$G = new GmailClient($hostname, $username, $password);
//turn off debugging after trying to load a problem class.
$AutoLoader->setDebug(false);
这是调试输出的内容
================================= Autoloader::debugMode ==================================
Autoloader::splAutoload Lib\Email\IMAP\GmailClient
Checking class: GmailClient
Checking namespace: Lib/Email/IMAP
checking pathname:C:/Server/www/MISC/IMAP/IMAP/GmailClient.php
==========================================================================================
我们可以立即看到C:/Server/www/MISC/IMAP/IMAP/GmailClient.php
IMAP在那里2倍。这是因为我在路径中包含了它,因此它开始查看C:/Server/www/MISC/IMAP/
,然后从IMAP
添加名称空间arg Lib/Email/IMAP
中未提供的命名空间。我们给它Lib/Email
作为第一个参数。基本上,因为这是路径的一部分,当它寻找时,它已经在该文件夹中。
所以如果我只是从路径中删除IMAP
:
$Autoloader->regesterPath('Lib\Email', __DIR__);
它将输出:
================================= Autoloader::debugMode ==================================
Autoloader::splAutoload Lib\Email\IMAP\GmailClient
Checking class: GmailClient
Checking namespace: Lib/Email/IMAP
checking pathname:C:/Server/www/MISC/IMAP/GmailClient.php
Found: C:/Server/www/MISC/IMAP/GmailClient.php
==========================================================================================
最重要的一行就是这个
Found: C:/Server/www/MISC/IMAP/GmailClient.php
这显然意味着它找到了类文件并加载了它。
希望这是有道理的。
以下是自动加载器的完整代码,这样,如果有任何与我关联的回购链接有任何变化,答案就不会中断。
<?php
/**
*
* (c) 2016 ArtisticPhoenix
*
* For license information please view the LICENSE file included with this source code. GPL-3
*
* PSR4 compatible Autoloader
*
* @author ArtisticPhoenix
* @see http://www.php-fig.org/psr/psr-4/
*
* @example
* $Autoloader = Autoloader::getInstance();
* //looks in includes for folder named /includes/Lib/Auth/User/
* $Autoloader->regesterPath('Lib\\Auth\\User', __DIR__.'/includes/');
*
*/
final class Autoloader
{
/**
*
* @var int
*/
const DEFAULT_PRIORITY = 10;
/**
* namespace / class path storage
* @var array
*/
private $paths = array();
/**
* cashe the loaded files
* @var array
*/
private $files = array();
/**
* namespace / class path storage
* @var array
*/
private $debugMode = false;
/**
*
* @var Self
*/
private static $instance;
/**
* No public construction allowed - Singleton
*/
private function __construct($throw, $prepend)
{
spl_autoload_register(array( $this,'splAutoload'), $throw, $prepend);
}
/**
* No cloning of allowed
*/
private function __clone()
{
}
/**
*
* Get an instance of the Autoloader Singleton
* @param boolean $throw
* @param boolean $prepend
* @return self
*/
public static function getInstance($throw = false, $prepend = false)
{
if (!self::$instance) {
self::$instance = new self($throw, $prepend);
}
return self::$instance;
}
/**
* set debug output
* @param boolean $debug
* @return self
*/
public function setDebug($debug = false)
{
$this->debugMode = $debug;
return $this;
}
/**
* Autoload
* @param string $class
*/
public function splAutoload($class)
{
$this->debugMode('_START_');
$this->debugMode(__METHOD__.' '.$class);
//keep the orignal class name
$_class = str_replace('\\', '/', $class);
$namespace = '';
if (false !== ($pos = strrpos($_class, '/'))) {
$namespace = substr($_class, 0, ($pos));
$_class = substr($_class, ($pos + 1));
}
//replace _ in class name only
if (false !== ($pos = strrpos($_class, '/'))) {
if (strlen($namespace)) {
$namespace .= '/'.substr($_class, 0, ($pos));
} else {
$namespace = substr($_class, 0, ($pos));
}
$_class = substr($_class, ($pos + 1));
}
$this->debugMode("Checking class: $_class");
$this->debugMode("Checking namespace: $namespace");
do {
if (isset($this->paths[ $namespace ])) {
foreach ($this->paths[ $namespace ] as $registered) {
$filepath = $registered['path'] . $_class . '.php';
$this->debugMode("checking pathname:{$filepath}");
if (file_exists($filepath)) {
$this->debugMode("Found: $filepath");
$this->debugMode('_END_');
require_once $filepath;
$this->files[$class] = $filepath;
}
}
}
if (strlen($namespace) == 0) {
//if the namespace is empty and we couldn't find the class we are done.
break;
}
if (false !== ($pos = strrpos($namespace, '/'))) {
$_class = substr($namespace, ($pos + 1)) . '/' . $_class;
$namespace = substr($namespace, 0, ($pos));
} else {
$_class = (strlen($namespace) ? $namespace : '') . '/' . $_class;
$namespace = '';
}
} while (true);
$this->debugMode('_END_');
}
/**
* get the paths regestered for a namespace, leave null go get all paths
* @param string $namespace
* @return array or false on falure
*/
public function getRegisteredPaths($namespace = null)
{
if (is_null($namespace)) {
return $this->paths;
} else {
return (isset($this->paths[$namespace])) ? array($namespace => $this->paths[$namespace]) : false;
}
}
/**
*
* @param string $namespace
* @param string $path
* @param int $priority
* @return self
*/
public function regesterPath($namespace, $path, $priority = self::DEFAULT_PRIORITY)
{
$namespace = str_replace('\\', '/', $namespace); //convert to directory seperator
$path = ($this->normalizePath($path));
$this->paths[$namespace][sha1($path)] = array(
'path' => $path,
'priority' => $priority
);
$this->sortByPriority($namespace);
return $this;
}
/**
* un-regester a path
* @param string $namespace
* @param string $path
*/
public function unloadPath($namespace, $path = null)
{
if ($path) {
$path = $this->normalizePath($path);
unset($this->paths[$namespace][sha1($path)]);
} else {
unset($this->paths[$namespace]);
}
}
/**
* check if a namespace is regestered
* @param string $namespace
* @param string $path
* @return bool
*/
public function isRegistered($namespace, $path = null)
{
if ($path) {
$path = $this->normalizePath($path);
return isset($this->paths[$namespace][sha1($path)]) ? true : false;
} else {
return isset($this->paths[$namespace]) ? true : false;
}
}
/**
* get the file pathname of a loaded class
* @param string $class
* @return mixed
*/
public function getLoadedFile($class = null)
{
if (!$class) {
return $this->files;
}
if (isset($this->files[$class])) {
return $this->files[$class];
}
}
/**
* output debug message
* @param string $message
*/
protected function debugMode($message)
{
if (!$this->debugMode) {
return;
}
switch ($message) {
case '_START_':
echo str_pad("= ".__METHOD__." =", 90, "=", STR_PAD_BOTH) . PHP_EOL;
break;
case '_END_':
echo str_pad("", 90, "=", STR_PAD_BOTH) . PHP_EOL . PHP_EOL;
break;
default:
echo $message . PHP_EOL;
}
}
/**
* sort namespaces by priority
* @param string $namespace
*/
protected function sortByPriority($namespace)
{
uasort($this->paths[$namespace], function ($a, $b) {
return ($a['priority'] > $b['priority']) ? true : false;
});
}
/**
* convert a path to unix seperators and make sure it has a trailing slash
* @param string $path
* @return string
*/
protected function normalizePath($path)
{
if (false !== strpos($path, '\\')) {
$path = str_replace("\\", "/", $path);
}
return rtrim($path, '/') . '/';
}
}
P.S。我在本例中使用的GmailClient类,用于解析Gmail帐户中的传入电子邮件。它不是100%充实,因为我们需要它用于特定目的。但它位于同一个GitHub存储库中。