PHP: проблемы с автоматической загрузкой
Я создаю веб-сайт и использую Apache в качестве своего веб-сервера.
Я создал сайт без использования классов. Все мои функции находятся в одном файле, и я просто включаю этот файл на каждой странице, где мне нужно использовать некоторые функции.
Сейчас я хочу перейти на подход ООП, но у меня возникли проблемы с пониманием того, как загружать мои классы автоматически. Я просмотрел ряд связанных страниц, таких как; пример PSR-4 , spl_autoload_register(), связанный с этим Вопрос , и я просто не могу понять, как это происходит.
Итак, поскольку я использую Apache, путь к корню моего веб-сайта является C:Apachehtdocs .
Мои каталоги выглядят следующим образом;
+ htdocs
+ Lib
+ Base
- User.php
- Device.php
- Company.php
- Database.php
+ Services
- UserService.php
- DeviceService.php
- CompanyServer.php
+ Config
- DbConfig.php
В качестве примера, чтобы вы могли помочь мне разобраться в этом, мы просто поговорим о двух классах DbConfig и Database.
DbConfig.php (с деталями подключения опущено)
<?PHP
namespace LibConfig;
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';
}
}
база данных.php (Очень простой, пока я не смогу его использовать-в этот момент я добавлю его функциональность)
<?PHP
namespace LibBase;
use LibConfigDbConfig;
class Database extends DbConfig
{
protected $connection;
private $dataSet;
private $sqlQuery;
public function __construct()
{
parent::__construct();
$this->connection = null;
$this->dataSet = null;
$this->sqlQuery = null;
}
}
Итак..
Как я загружаю эти классы, используя некоторую реализацию spl_autoload_register () , в другой .php файл, чтобы я мог использовать их для создания объектов? например, в файле с именем 'тестирование.php'
-
Ранее я бы разбирал a .ini файл за пределами чтобы получить сведения о соединении с базой данных, я должен сделать это с помощью моего нового подхода, имеющего сведения о соединении в классе DbConfig ?
3 ответа:
Согласно стандарту PSR-4,
Полное имя класса должно иметь имя пространства имен верхнего уровня, также известное как"пространство имен поставщика".Похоже, в ваших классах этого нет. Чтобы добавить его, измените
Затем, используя автозагрузчик PSR-4, на который вы ссылались, изменитеnamespace Lib\Config;
, например, наnamespace AskMeOnce\Lib\Config;
. Вам нужно будет добавить этот префикс ко всем вашим классам.$prefix = 'Foo\\Bar\\';
на$prefix = 'AskMeOnce\\';
и$base_dir = __DIR__ . '/src/';
на$base_dir = 'C:\Apache\htdocs';
. Поместите эту функцию в файл с именем autoload.php, и требовать его в любой файл, который должен знать, как выполнить автоматическую загрузку.После того, как Вы
Чтобы ответить на ваши вопросы конкретно, (1) Просто поместите функцию вrequire
этот загрузчик, PHP будет знать, чтобы искать любой класс, который начинается с пространства именAskMeOnce
в указанном базовом каталоге. После удаления этого префикса из пространства имен пространство имен представляет собой остальную часть пути. Например,AskMeOnce\Lib\Config\DbConfig
будет искать в<basedir>/Lib/Config/DbConfig.php
.autoload.php
с изменениями, о которых я упоминал выше. И (2) поскольку ini-файл является не класс PHP, не имеет значения, где он находится, пока ваш код знает, как его найти (является ли это жестко закодированный путь или нет).
Вот краткий пример, который я собрал вместе:
Создайте файл с именем
autoloader.php
. Этот пример был взят из примеровPSR-4 . Измените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
в качестве примера. Это называетсяинъекцией зависимостей .Еще один пример:
Lib/Services/UserService.php
:<?php namespace Acme\Services; class UserService { ... }
Теперь вы можете вызвать это в коде (при условии, что автозагрузчик включен) следующим образом:
$userService = new \Acme\Services\UserService;
Я бы также рекомендовал проверить Composer. Очень полезно, если вы хотите использовать общедоступные пакеты из Packagist, и очень легко создать свой собственный. Поддерживает автозагрузку PSR - * (PSR4 наиболее распространен).
Зарегистрируйте функцию автоматической загрузки:
Добавить код в любой файл можно перед использованием других классов библиотеки 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);
Не рекомендуется использовать пространство имен, если ваш проект недостаточно велик, просто используйте имя каталога и файла, чтобы сделать это