Unable to start project in Kohana. I have cloned it from github, than set my database info in config file and get error: Cannot redeclare class.
I have 2 methods autoload functions.
public static function auto_load($class, $directory = 'classes')
{
// Transform the class name according to PSR-0
$class = ltrim($class, '\\');
$file = '';
$namespace = '';
if ($last_namespace_position = strripos($class, '\\'))
{
$namespace = substr($class, 0, $last_namespace_position);
$class = substr($class, $last_namespace_position + 1);
$file = str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR;
}
$file .= str_replace('_', DIRECTORY_SEPARATOR, $class);
if ($path = Kohana::find_file($directory, $file))
{
// Load the class file
require_once $path;
// Class has been found
return TRUE;
}
// Class is not in the filesystem
return FALSE;
}
/**
* Provides auto-loading support of classes that follow Kohana's old class
* naming conventions.
*
* This is included for compatibility purposes with older modules.
*
* #param string $class Class name
* #param string $directory Directory to load from
* #return boolean
*/
public static function auto_load_lowercase($class, $directory = 'classes')
{
// Transform the class name into a path
$file = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class));
if ($path = Kohana::find_file($directory, $file))
{
// Load the class file
require_once $path;
// Class has been found
return TRUE;
}
// Class is not in the filesystem
return FALSE;
}
I have tried to add class_exists() before require() but it doesn't work& What I should do to start a project?
Possibly required class is included in some other file already.
I don't know how exactly you check class collision problem, but you should do something like:
function include_quietly($file) {
$conflicts = false;
$txt = file_get_contents($file);
preg_match_all("#class\s+(\w+)\s*{#muis", $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
if (class_exists($m[1])) {
$conflicts = true;
break;
}
}
if (!$conflicts)
include_once $file;
else
echo "include conflicts in file {$file}\n";
}
include_quietly($path);
Related
I'm testing PSR-4 autoloader from https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md and something is not working.
Error:
Fatal error: Uncaught Error: Class 'Foo\Bar\Qux\Quux' not found in C:\xampp\htdocs\Home\foo-bar\index.php:11 Stack trace: #0 {main} thrown in C:\xampp\htdocs\Home\foo-bar\index.php on line 11
Line:
new \Foo\Bar\Qux\Quux;
My files:
index.php
example
loader.php
src
Qux
Quux.php
Baz.php
tests
Qux
Quux.php
BazTest.php
index.php:
<?php
require_once "Example/loader.php";
$loader = new \Example\Psr4AutoloaderClass;
$loader->register();
$loader->addNamespace('Foo\Bar', '/src');
$loader->addNamespace('Foo\Bar', '/tests');
new \Foo\Bar\Qux\Quux;
loader.php:
<?php namespace Example;
class Psr4AutoloaderClass
{
protected $prefixes = array();
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
}
public function addNamespace($prefix, $base_dir, $prepend = false)
{
// normalize namespace prefix
$prefix = trim($prefix, '\\') . '\\';
// normalize the base directory with a trailing separator
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
// initialize the namespace prefix array
if (isset($this->prefixes[$prefix]) === false) {
$this->prefixes[$prefix] = array();
}
// retain the base directory for the namespace prefix
if ($prepend) {
array_unshift($this->prefixes[$prefix], $base_dir);
} else {
array_push($this->prefixes[$prefix], $base_dir);
}
}
public function loadClass($class)
{
// the current namespace prefix
$prefix = $class;
while (false !== $pos = strrpos($prefix, '\\')) {
// retain the trailing namespace separator in the prefix
$prefix = substr($class, 0, $pos + 1);
// the rest is the relative class name
$relative_class = substr($class, $pos + 1);
// try to load a mapped file for the prefix and relative class
$mapped_file = $this->loadMappedFile($prefix, $relative_class);
if ($mapped_file) {
return $mapped_file;
}
$prefix = rtrim($prefix, '\\');
}
return false;
}
protected function loadMappedFile($prefix, $relative_class)
{
// are there any base directories for this namespace prefix?
if (isset($this->prefixes[$prefix]) === false) {
return false;
}
foreach ($this->prefixes[$prefix] as $base_dir) {
$file = $base_dir
. str_replace('\\', '/', $relative_class)
. '.php';
// if the mapped file exists, require it
if ($this->requireFile($file)) {
// yes, we're done
return $file;
}
}
// never found it
return false;
}
protected function requireFile($file)
{
if (file_exists($file)) {
require $file;
return true;
}
return false;
}
}
Quux.php:
<?php namespace Foo\Bar\Qux;
class Quux {
public function __construct() {
echo "Hello";
}
}
Thank you for your help.
Change this in your index.php:
$loader->addNamespace('Foo\Bar\Qux', __DIR__ . '/src/Qux');
$loader->addNamespace('Foo\Bar\Qux', __DIR__ . '/tests/Qux');
There is an error in the PSR-4-autoloader-examples.md documentation.
I'm having trouble with this very confusing error. I have a class and an extended class. If my extended file name starts with a capital B then it cannot find my database class. If I name anything else, literally anything else it works.
My database class looks like so
class Database
{
public $db;
public function __construct()
{
if (DATABASE == true)
{
$this->db = new mysqli(HOSTNAME, USERNAME, PASSWORD, DBNAME);
if ($this->db->connect_error)
{
exit('Some of the database login credentials seem to be wrong.' . '-' . $this->db->connect_error);
}
}
}
}
my extended class is like so
class BlogModel extends Database
{
public function getBlogPosts()
{
$query = array();
if ($result = $this->db->query('SELECT * FROM blog'))
{
while ($row = $result->fetch_assoc())
{
$query[] = $row;
}
$result->free();
}
return $query;
$mysqli->close();
}
}
The filename BlogModel.php causes the error.
Fatal error: Class 'Database' not found in C:\wamp\www\website\app\model\BlogModel.php on line 4
If I change it to blogModel.php it works. I don't mind just changing the filename but in the interest of understanding and learning I'd like to know why this is happening.
Edit:
This is how I include the files
define('ROOT', str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']));
define('HOST', $_SERVER['HTTP_HOST']);
define('URL', $_SERVER['REQUEST_URI']);
define('APP', ROOT . '/app/');
define('MODEL', ROOT . '/app/model/');
define('VIEW', APP . '/view/');
define('CONTROLLER', ROOT . '/app/controller/');
$models = array_diff(scandir(MODEL), array('.', '..'));
foreach ($models as $m)
{
require_once MODEL . $m;
}
To use an autoloader that is PSR compliant you would need to restructure your directory tree.
The code I use is a (not fully) PSR-4 compliant code:
<?php
#cn is class name
#fn is file name
#ns is namespace
#np is namespace pointer
class Loader{
public function load($class){
$cn = ltrim($class, '\\');
$fn = '';
$ns = '';
if($np = strrpos($cn, '\\')){
$ns = substr($cn, 0, $np);
$cn = substr($cn, $np + 1);
$fn = str_replace('\\', DIRECTORY_SEPARATOR, $ns) . DIRECTORY_SEPARATOR;
}
require ($fn .= strtolower(str_replace('_', DIRECTORY_SEPARATOR, $cn)) . '.php');
}
public function __construct(){
spl_autoload_register([$this, 'load']);
}
}
new Loader;
?>
It will load files in a lower case filename, if you do not use namespaces it will attempt to load from the document root if the object does not exist.
If you are using namespaces, aka:
$var = new \path\to\ObjeCt();
It would attempt to load object.php from webroot\path\to\
How one would use this is simple, just include this file and the next time you create an object keep the namespace valid to the path.
I'm new to PHP namespace. and there is a problem when I use auto-load.
ROOT/Application/Instance.php
<?php
namespace Application;
class Instance {
public static $_database;
public function __construct() {
self::$_database = new \Application\Module\Database();
}
public static function database() {
return self::$_database;
}
public static function ID(){
return md5(uniqid(mt_rand(), TRUE) . mt_rand() . uniqid(mt_rand(), TRUE));
}
public static function autoload($_className) {
$thisClass = str_replace(__NAMESPACE__.'\\', '', __CLASS__);
$baseDir = __DIR__;
if (substr($baseDir, -strlen($thisClass)) === $thisClass) {
$baseDir = substr($baseDir, 0, -strlen($thisClass));
}
$_className = ltrim($_className, '\\');
$fileName = $baseDir;
$namespace = '';
if ($lastNsPos = strripos($_className, '\\')) {
$namespace = substr($_className, 0, $lastNsPos);
$_className = substr($_className, $lastNsPos + 1);
$fileName .= str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $_className) . '.php';
if (file_exists($fileName)) {
require $fileName;
}
}
public static function registerAutoloader() {
spl_autoload_register(__NAMESPACE__ . "\\Instance::autoload");
}
}
ROOT/Application/Module/Database.php
<?php
namespace Application\Module;
include 'FluentPDO/FluentPDO.php';
class Database extends Module {
public static $_instance;
public function __construct() {
if(self::$_instance === NULL) {
self::$_instance = new FluentPDO(new PDO("mysql:host=8273639.mysql.rds.aliyuncs.com;dbname=db", 'name', 'password'));
}
}
}
When I run this:
new \Application\Instance();
I got this error:
Fatal error: Class 'Application\Module\FluentPDO' not found in /mnt/www/airteams_com/public/Application/Module/Database.php on line 13
I'm pretty sure that 'FluentPDO/FluentPDO.php' exists. and the error shows a wrong path of the file. the right path is 'ROOT/Application/Module/FluentPDO/FluentPDO.php'
So how can i use a no namespace class in my situation? thanks.
When you are working with namespaces you must fully qualify each class unless it's a child of the current namespace.
As such the FluentPDO is probably on the root namespace which means you need to access it like such:
self::$_instance = new \FluentPDO(new \PDO("mysql:host=8273639.mysql.rds.aliyuncs.com;dbname=db", 'name', 'password'));
I am makeing a small framework for scheduled job that are run by a nodejs external process. I would like to use an auto loader but for some reason data is not getting to it. I am also using namespaces. Here is what my folder structure looks like:
Library
|_ Core
|_ JobConfig.php
|_ Utilities
|_ Loader.php
|_ Scheduled
|_ SomeJob.php
|_ Config.php
My Config.php just has some definitions and an instance of my Loader.php.
Loader.php looks like:
public function __constructor()
{
spl_autoload_register(array($this, 'coreLoader'));
spl_autoload_register(array($this, 'utilitiesLoader'));
}
private function coreLoader($class)
{
echo $class;
return true;
}
private function utilitiesLoader($lass)
{
echo $class;
return true;
}
So for my SomeJob.php I am including Config.php and then try to instantiate JobConfig.php when it fails. My namespaces look like Library\Core\JobConfig and so on. I am not sure if this is the best approach without the ability to bootsrapt things. But I am not seeing the echo's from the loader before it fails.
Edit:
I tried the sugestion by #Layne but did not work. I am still getting a class not found and seems like the class in not getting in the spl stack. Here is a link to the code
If you actually use namespaces in the same way you're using your directory structure, this should be rather easy.
<?php
namespace Library {
spl_autoload_register('\Library\Autoloader::default_autoloader');
class Autoloader {
public static function default_autoloader($class) {
$class = ltrim($class, '\\');
$file = __DIR__ . '/../';
if ($lastNsPos = strrpos($class, '\\')) {
$namespace = substr($class, 0, $lastNsPos);
$class = substr($class, $lastNsPos + 1);
$file .= str_replace('\\', '/', $namespace) . '/';
}
$file .= $class . '.php';
include $file;
}
}
}
Put that into your Library directory and require it on a higher level. Hopefully I didn't mess that one up, didn't test it.
EDIT: Fixed path.
use this class to index of your project, just replace WP_CONTENT_DIR with another directory level to scan php files, this class automatically include files:
<?php
class autoloader
{
public static function instance()
{
static $instance = false;
if( $instance === false )
{
// Late static binding
$instance = new static();
}
return $instance;
}
/**
* #param $dir_level directory level is for file searching
* #param $php_files_json_name name of the file who all the PHP files will be stored inside it
*/
private function export_php_files($dir_level, $php_files_json_name)
{
$filePaths = array(mktime());
/**Get all files and directories using iterator.*/
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir_level));
foreach ($iterator as $path) {
if (is_string(strval($path)) and pathinfo($path, PATHINFO_EXTENSION) == 'php') {
$filePaths[] = strval($path);
}
}
/**Encode and save php files dir in a local json file */
$fileOpen = fopen($dir_level . DIRECTORY_SEPARATOR . $php_files_json_name, 'w');
fwrite($fileOpen, json_encode($filePaths));
fclose($fileOpen);
}
/**
* #param $php_files_json_address json file contains all the PHP files inside it
* #param $class_file_name name of the class that was taken from #spl_autoload_register_register plus .php extension
* #return bool Succeeding end of work
*/
private function include_matching_files($php_files_json_address, $class_file_name)
{
static $files;
$inc_is_done = false;
if ($files == null) {
$files = json_decode(file_get_contents($php_files_json_address), false);
}
/**Include matching files here.*/
foreach ($files as $path) {
if (stripos($path, $class_file_name) !== false) {
require_once $path;
$inc_is_done = true;
}
}
return $inc_is_done;
}
/**
* #param $dir_level directory level is for file searching
* #param $class_name name of the class that was taken from #spl_autoload_register
* #param bool $try_for_new_files Try again to include new files, that this feature is #true in development mode
* it will renew including file each time after every 30 seconds #see $refresh_time.
* #return bool Succeeding end of work
*/
public function request_system_files($dir_level, $class_name, $try_for_new_files = false)
{
$php_files_json = 'phpfiles.json';
$php_files_json_address = $dir_level . DIRECTORY_SEPARATOR . $php_files_json;
$class_file_name = $class_name . '.php';
$files_refresh_time = 30;
/**Include required php files.*/
if (is_file($php_files_json_address)) {
$last_update = json_decode(file_get_contents($php_files_json_address), false)[0];
if ((mktime() - intval($last_update)) < $files_refresh_time || !$try_for_new_files) {
return $this->include_matching_files($php_files_json_address, $class_file_name);
}
}
$this->export_php_files($dir_level, $php_files_json);
return $this->include_matching_files($php_files_json_address, $class_file_name);
}
/**
* Make constructor private, so nobody can call "new Class".
*/
private function __construct()
{
}
/**
* Make clone magic method private, so nobody can clone instance.
*/
private function __clone()
{
}
/**
* Make sleep magic method private, so nobody can serialize instance.
*/
private function __sleep()
{
}
/**
* Make wakeup magic method private, so nobody can unserialize instance.
*/
private function __wakeup()
{
}
}
/**
* Register autoloader.
*/
try {
spl_autoload_register(function ($className) {
$autoloader = autoloader::instance();
return $autoloader->request_system_files(WP_CONTENT_DIR, $className, true);
});
} catch (Exception $e) {
var_dump($e);
die;
}
I have a PHP script which is producing the following error
Parse error: syntax error, unexpected '[', expecting ')' in /home/masked/public_html/masked/AutoLoader.php on line 20
(note that I masked some parts of the directory given as they correspond with personal info.)
(line 20 is spl_autoload_register([$autoloader, 'load']); found in the register function.
I am running PHP 5.5
I have also tried it with PHP 5.3.27 and get the exact same result.
code bellow
run.php
require_once 'AutoLoader.php';
AutoLoader::register('src');
AutoLoader.php
/**
* A basic PSR style autoloader
*/
class AutoLoader
{
protected $dir;
protected $ext;
public function __construct($dir, $ext = '.php')
{
$this->dir = rtrim($dir, DIRECTORY_SEPARATOR);
$this->ext = $ext;
}
public static function register($dir, $ext = '.php')
{
$autoloader = new static($dir, $ext);
spl_autoload_register([$autoloader, 'load']);
return $autoloader;
}
public function load($class)
{
$dir = $this->dir;
if ($ns = $this->get_namespace($class)) {
$dir .= DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $ns);
}
$inc_file = $dir.DIRECTORY_SEPARATOR.$this->get_class($class).$this->ext;
if (file_exists($inc_file)) {
require_once $inc_file;
}
}
// Borrowed from github.com/borisguery/Inflexible
protected static function get_class($value)
{
$className = trim($value, '\\');
if ($lastSeparator = strrpos($className, '\\')) {
$className = substr($className, 1 + $lastSeparator);
}
return $className;
}
// Borrowed from github.com/borisguery/Inflexible
public static function get_namespace($fqcn)
{
if ($lastSeparator = strrpos($fqcn, '\\')) {
return trim(substr($fqcn, 0, $lastSeparator + 1), '\\');
}
return '';
}
}
On run.php try:
require_once('Autoloader.php');