PHP:自动加载问题

时间:2016-02-22 14:54:23

标签: php apache oop autoload

我正在创建一个网站,我正在使用Apache作为我的网络服务器。

我创建了一个不使用类的网站。我的所有函数都位于一个文件中,我只是在每个需要使用某些函数的页面上包含此文件。

我现在想要换成OOP方法,但我无法理解如何自动加载我的类。我已经通过了一些相关的页面,如; PSR-4 Examplespl_autoload_register()Related Question而我似乎无法理解这一点。

因此,当我使用Apache时,我网站根目录的路径是 C:\ Apache \ htdocs

我的目录如下所示;

+ htdocs
    + Lib
        + Base
            - User.php
            - Device.php
            - Company.php
            - Database.php
        + Services
            - UserService.php
            - DeviceService.php
            - CompanyServer.php
        + Config
            - DbConfig.php

作为一个例子,你可以帮助我解决这个问题,我们将讨论两个类 DbConfig 数据库

DbConfig.php (省略连接细节)

<?PHP
namespace Lib\Config;

class DbConfig
{
    protected $serverName;
    protected $userName;
    protected $password;
    protected $dbName;

   public function __construct()
    {
        $this->serverName = 'not my server name';
        $this->userName = 'not my username';
        $this->passCode = 'not my password';
        $this->dbName = 'not my database';
    }
}

Database.php (非常简单,直到我可以实际使用它 - 此时我将添加其功能)

<?PHP
namespace Lib\Base;

use Lib\Config\DbConfig;

class Database extends DbConfig
{
    protected $connection;
    private $dataSet;
    private $sqlQuery;

    public function __construct()
    {
        parent::__construct();      
        $this->connection = null;
        $this->dataSet = null;
        $this->sqlQuery = null;
    }
}

所以......

  1. 如何使用 spl_autoload_register()的一些实现将这些类加载到另一个 .php 文件中,以便我可以使用它们来创建对象?例如,在名为“ Testing.php

  2. 的文件中
  3. 以前我会在我的文件夹根目录之外解析一个 .ini 文件以获取数据库连接的详细信息,我是否应该使用我的新方法来获取连接详细信息class DbConfig

3 个答案:

答案 0 :(得分:1)

根据PSR-4标准,

  

完全限定的类名必须具有顶级命名空间名称,也称为“供应商命名空间”。

你的课程似乎没有这个。要添加它,请将namespace Lib\Config;更改为,例如namespace AskMeOnce\Lib\Config;。您需要将此前缀添加到所有类中。

然后,使用您引用的PSR-4自动加载器,将$prefix = 'Foo\\Bar\\';更改为$prefix = 'AskMeOnce\\';,将$base_dir = __DIR__ . '/src/';更改为$base_dir = 'C:\Apache\htdocs';。将该函数放在名为autoload.php的文件中,并在需要知道如何自动加载的任何文件中要求它。

一旦你require自动加载器,PHP将知道在指定的基目录中查找以名称空间AskMeOnce开头的任何类。从命名空间中删除该前缀后,命名空间代表路径的其余部分。例如,AskMeOnce\Lib\Config\DbConfig会查找<basedir>/Lib/Config/DbConfig.php

具体回答你的问题,(1)只需将功能放在autoload.php中,并进行上述修改。并且(2)由于ini文件不是PHP类,只要你的代码知道如何找到它(无论这是硬编码路径还是其他方式),它在哪里都无关紧要。

答案 1 :(得分:1)

这是一个简单的例子:

创建一个名为autoloader.php的文件。此示例取自PSR-4 Examples。将Acme更改为您的项目名称。

这将允许您使用名称空间,只要它们存储在Lib/下并且您将名称空间添加到每个文件中(就像您已经在做的那样)。

<?php
/**
 * An example of a project-specific implementation.
 * @param string $class The fully-qualified class name.
 * @return void
 */
spl_autoload_register(function ($class) {

    // project-specific namespace prefix
    $prefix = 'Acme\\';

    // base directory for the namespace prefix
    $base_dir = __DIR__ . '/Lib/';

    // does the class use the namespace prefix?
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        // no, move to the next registered autoloader
        return;
    }

    // get the relative class name
    $relative_class = substr($class, $len);

    // replace the namespace prefix with the base directory, replace namespace
    // separators with directory separators in the relative class name, append
    // with .php
    $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
    print $file;
    // if the file exists, require it
    if (file_exists($file)) {
        require $file;
    }
});

这使用spl_autoload_register来处理依赖项/类的自动加载,并允许使用PRS-4名称空间。

接下来,您的Database课程将存储在Lib/Base/Database.php

<?php

namespace Acme\Base;

class Database
{
    private $db;

    public function __construct(\PDO $db)
    {
        $this->db = $db;
    }

    public function allUsers()
    {
        /*
         * Query to fetch all users from the database
         */

        return [
            [
                'username' => 'Bob',
                'role' => 'member'
            ],
            [
                'username' => 'Joe',
                'role' => 'admin'
            ]
        ];
    }
}

最后,您的索引页面包含autoloader.php脚本,该脚本自动包含类。

<?php

require_once 'autoloader.php';

$config = require 'config.php';

try {
    $dbc = new PDO("mysql:dbname={$config['MYSQL']['DATABASE']};host={$config['MYSQL']['HOST']}",
                   $config['MYSQL']['USERNAME'], $config['MYSQL']['PASSWORD']);
} catch (PDOException $e) {
    die('Could not connect to database ' . $e->getMessage());
}

$db = new \Acme\Database($dbc);
print_r($db->allUsers());

最后,您询问了配置文件。我使用像这样的配置文件:

<?php

return [
    'MYSQL' => [
        'USERNAME' => 'root',
        'PASSWORD' => '',
        'DATABASE' => 'test',
        'HOST' => 'localhost'
    ]
];

这允许您将配置文件包含在一个简单的:

$config = require 'config.php';

并且如此访问:

$config['MYSQL']['USERNAME'];

我将\PDO数据库连接作为依赖项传递给Database类作为示例。这称为Dependency Injection

另一个例子:Lib/Services/UserService.php

<?php

namespace Acme\Services;

class UserService
{
    ...
}

您现在可以在代码中调用此代码(如果包含自动加载器),如下所示:

$userService = new \Acme\Services\UserService;

我还建议您查看Composer。如果您想使用Packagist中的公共包,则非常有用,而且您可以轻松创建自己的包。也支持PSR- *自动加载(PSR4最常见)。

答案 2 :(得分:0)

注册自动加载功能:

在使用其他php库类之前,可以在任何文件中添加代码,例如在项目条目文件中。

defined('ROOT') or define('ROOT', 'C:/Apache/htdocs');
// define root directory
// or `defined('ROOT') or define('ROOT', __DIR__)` if
// the file is in the root directory

spl_autoload_register(function($name) {
    $file = ROOT . "/{$name}.php";
    if(!is_file($file)) {
        return false;
    } else {
        return include $file;
    }
}, false, true);

如果您的项目不够大,建议不要使用命名空间,只需使用目录和文件名来执行此操作