致命错误:未捕获错误:找不到“App \ Database”类

时间:2018-04-07 07:58:29

标签: php

我尝试学习oop但是在我的第一堂课中它给了我这个错误。

数据库类

<?php
namespace App;

class Database
{
   ...
}

在我的functions.php

<?php
require 'helpers.php';
require 'connection.php';
use App\Database;
...

“app”文件夹下的类,它的命名空间是“App”。为什么我收到此错误?

2 个答案:

答案 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存储库中。