Its the first time working with an autoloader and getting some errors.
The structure is as follows:
AnimalShop (root)
classes
Shop.php
index.php
I have the following simple code
Index.php
<?php
spl_autoload_register(function ($class_name)
{
include $class_name . '.php';
});
echo "<h1>PETs SHOP</h1>";
// Create a shop
$shop = new Shop();
Shop is a simple class
<?php
namespace PHPAdvanced\AnimalShop\classes;
/*
* Pet shop
*/
class Shop
{
/**
* #var Pets[] pets
*/
private $pets = [];
public function addPetsToArray(Pets $pet)
{
$this->pets[] = $pet;
}
/**
* Print pets naam
*/
public function printPets()
{
foreach($this->pets as $pet)
{
echo "<p>" . $pet->getPetNaam() . "</p>";
}
}
}
When i run index.php i get the following errors:
Warning: include(Shop.php): failed to open stream: No such file or directory in /var/www/phpadvancedCourse/AnimalShop/index.php on line 4
Warning: include(): Failed opening 'Shop.php' for inclusion (include_path='.:/usr/share/php:') in /var/www/phpadvancedCourse/AnimalShop/index.php on line 4
spl_autoload_register(function ($class_name)
{
include realpath(dirname(__FILE__))."/classes/".$class_name . '.php';
});
your path is wrong.. try this..
To solve the problem i have used PSR-4 autoloading through composer with the following structure and code.
Structure
AnimalShop (root)
index.php
App (Folder)
Behavior (Folder)
WalkBehavior.php (interface)
Pets(Folder)
Cat.php
Dog.php
Fish.php
Pets.php (abstract class)
Shop(Folder)
PetShop.php
Composer.json
{
"autoload" : {
"psr-4" : {
"App\\" : "App"
}
}
}
index.php
<?php
// Autoload
require "vendor/autoload.php";
use App\Shop\PetShop;
use App\Pets\Dog;
use App\Pets\Fish;
use App\Pets\Cat;
echo "<h1>PETs SHOP</h1>";
// Create a shop
$shop = new PetShop();
$shop->addPetsToArray(new Dog("Yuki"));
$shop->addPetsToArray(new Fish("BLubie"));
$shop->addPetsToArray(new Cat("Cattie"));
$shop->printPets();
Example of Petshop and Dog
<?php
namespace App\Shop;
use App\Pets\Pets;
/*
* Pet shop
*/
class PetShop
{
/**
* #var Pets[] pets
*/
private $pets = [];
public function addPetsToArray(Pets $pet)
{
$this->pets[] = $pet;
}
/**
* Print pets naam
*/
public function printPets()
{
foreach($this->pets as $pet)
{
echo "<p>" . $pet->getPetNaam() . "</p>";
}
}
}
DOG
<?php
namespace App\Pets;
/**
* Class Dog
*/
class Dog extends Pets
{
/**
* Dog constructor.
*
* #param $name
*/
public function __construct(string $name)
{
parent::__construct($name);
}
public function walk() : string
{
return "Dog is walking";
}
}
Related
I have this file root/core/Router.php
<?php
namespace Core;
class Router {
protected $url;
protected $controller;
private function parseURL() {
// threat the $this->url; for example ["r", "product"]
}
private function request() {
$this->controller = Controller::get($this->url[1]);
}
public function __construct() {
$this->parseURL();
$this->request();
}
}
?>
then file root/core/Controller.php
<?php
namespace Core;
class Controller {
public static function model($name, $params = []) {
$model = "\\Model\\$name";
return new $model($params);
}
public static function view($name, $params = []) {
require_once APP_DIR . "view/" . $name . ".php";
}
public static function get($name, $params = []) {
require_once APP_DIR . "controller/" . $name . ".php";
$name = "\\Controller\\$name";
return new $name($params);
}
}
?>
then root/controler/Product.php
<?php
namespace Controller;
use Core\Controller;
use Model\Product;
class Product {
public function get() {
$ret['state'] = 510;
$productModel = new Product;
$products = $productModel->getAll();
if(isset($products)) {
$ret['products'] = $products;
$ret['state'] = 200;
}
return $ret;
}
}
?>
then file root/model/Product.php
<?php
namespace Model;
class Product {
public function add($values) {
return Database::insert("product", $values);
}
}
?>
and root/core/Model.php
<?php
namespace Core;
class Model {
protected $table = null;
public function getAll() {
// some code to collect data
}
}
?>
What i want to achive is that every Controller in root/controller/*.php able to load any Model in root/model/*.php but class inside root/model/*.php must able to access (inheritance/extends) the Model class inside root/core/Model.php i firstly asked on chatGPT for some AI Generated answer, that the reason why i get this far.
Then i get this error, when the AI keep giving the same answer.
Fatal error: Cannot declare class Controller\Product because the name is already in use in C:\xampp\htdocs\app\shop\controller\Product.php on line 6
I actually realize that the simple way probably with naming the class so ther no conflict between it but i became aware how to properly using the namespace if its such features in php. Those files loaded without any autoloader, so i just require_once each file in root/init.php file.
I read few documentations but hard to implement in multiple files and directorys.
I Apreciate any feedback, thanks
My autoload is not working in wordpress (It's Not including the files), What can the problem be ?
If you read my comments you will understand it i think.
I am already trying the hole day to fix this problem. So if somebody knows the solution i really want to hear it : )
<?php
/*
Plugin Name: Test Autoload
Plugin URI: http://autoload.com
Description: Test Autoload
Version: 1.0
*/
if(!class_exists('Test_Autoload')) {
final class Test_Autoload {
public function __construct() {
Test_Autoload::register();
}
/**
* Registers Test_Autoload Loader as an SPL autoloader.
*
* #param boolean $prepend
*/
public static function register($prepend = false)
{
if (version_compare(phpversion(), '5.3.0', '>=')) {
spl_autoload_register(array(new self, 'autoload'), true, $prepend);
} else {
spl_autoload_register(array(new self, 'autoload'));
}
}
/**
* Handles autoloading of Test_Autoload classes.
*
* #param string $class
*/
public static function autoload($class)
{
$class = plugin_dir_path(__FILE__) . 'admin/classes/' . $class .'.php';
// If the specified $class does not include our namespace return
if ( false === strpos( $class, 'Test_Autoload' ) ) {
return;
}
if (is_file($class)) {
require_once($class);
} else {
wp_die("The file attempting to be loaded at $class does not exist.");
}
}
}
}
A simple and functionnal class to autoload with or withour namespaces
enter link description here
Hi Guys I'm working on a MVC based php application.In my include.php which is also in the server root of my server has following codes in order to fetch model and controller automatically from Controller folder inside the application directory of the server root.
My project directory is like this
accountBook
|-Application
| |-Controller
| | |-IndexController.php
| | |-baseController.php
| |_-Model
|-Content
|-index.php
|-config.php
|-includes.php
<?php
/*
*#Package Name: accountBook/includes.php
*#Date(Last Modified): Thru, Sept 15 - 2016
*#Author: Ajax Hill
*/
namespace accountBook
{
use accountBook\Application\Controller;
class accessControl
{
private $args,$type,$nature;
private static function route()
{
define('DS',DIRECTORY_SEPARATOR);
define('ROOT',getcwd().DS);
define('CONF', ROOT.'config.php');
include_once(CONF);
$con= new PDO;
if($result=$con->query('SELECT theme from sys_def'))
{
while($row=$result->fetch(PDO::FETCH_ASSOC))
{
define('THEME_NAME',$row['theme']);
}
}
else
{
echo "ERROR: Could not execute".print_r($pdo->errorInfo());
}
/*
* #var THEME_NAME(view) has been Fetch from Database
*/
define('CONTENT', ROOT.'content'.DS);
define('THEME_PATH',CONTENT.'themes'.DS.THEME_NAME.DS);
define('APP',ROOT.'Application'.DS);
define('CONTROL_PATH',APP.'contollers'.DS);
define('MODEL_PATH',APP.'models'.DS);
// index.php?p=admin&c=Goods&a=add
define("PLATFORM", isset($_REQUEST['p']) ? $_REQUEST['p'] : 'home');
define("CONTROLLER", isset($_REQUEST['c']) ? $_REQUEST['c'] : 'Index');
define("ACTION", isset($_REQUEST['a']) ? $_REQUEST['a'] : 'index');
unset($con);
}
// Autoloading
private static function autoload()
{
// Controller
require_once CONTROL_PATH. "{$classname}.php";
}
elseif (substr($classname, -5) == "Model")
{
// Model
require_once MODEL_PATH . "{$classname}.php";
}
}
// Routing and dispatching
private static function dispatch()
{
// Instantiate the controller class and call its action method
$controller_name = CONTROLLER . "Controller";
$action_name = ACTION . "Action";
$controller = new $controller_name;
$controller->$action_name();
}
public function __construct($type, $args,$nature='show')
/**
* var #type has two values = account | toDo
* var #type is post title
* var #nature is to determine the nature
*/
{
$this->args=$args;
$this->type=$type;
$this->nature=$nature;
self::route();
self::autoload();
self::dispatch();
}
}
}
Now I've create IndexController.php in Application folder
<?php
/**
*#Package Name: accountBook/Application/Controller/IndexController.php
*#Date(Last Modified): Thru, Sept 15 - 2016
*#Author: Ajax Hill
*/
namespace accountBook\Application\controller;
class IndexController extends baseController
{
public function mainAction(){
include THEME_PATH. "main.html";
// Load Captcha class
$this->loader->library("Captcha");
$captcha = new Captcha;
$captcha->hello();
$userModel = new UserModel("user");
$users = $userModel->getUsers();
}
public function indexAction(){
$userModel = new UserModel("user");
$users = $userModel->getUsers();
// Load View template
include THEME_PATH . "index.php";
}
public function menuAction(){
include THEME_PATH . "menu.php";
}
public function dragAction(){
include THEME_PATH . "drag.php";
}
public function topAction(){
include THEME_PATH . "top.php";
}
}
When Loading index file which has included includes.php I'm getting Following error
fetal error at line 67 not found path c://phpproj/accountBook/Application/Controller/accountBook/Application/Controller/baseController.php
Now Please help me adjust so that baseController fetch from c://phpproj/accountBook/Application/Controller/baseController.php
Your Class should have read something like:
<?php
/*
*#Package Name: accountBook/includes.php
*#Date(Last Modified): Thru, Sept 15 - 2016
*#Author: Ajax Hill
*/
namespace accountBook;
use accountBook\Application\Controller;
class accessControl {
private $args,$type,$nature;
private static function route(){
define('DS',DIRECTORY_SEPARATOR);
define('ROOT',getcwd().DS);
define('CONF', ROOT.'config.php');
include_once(CONF);
$con= new PDO;
if($result=$con->query('SELECT theme from sys_def')) {
while($row=$result->fetch(PDO::FETCH_ASSOC)){
define('THEME_NAME',$row['theme']);
}
}else{
echo "ERROR: Could not execute".print_r($pdo->errorInfo());
}
/*
* #var THEME_NAME(view) has been Fetch from Database
*/
define('CONTENT', ROOT.'content'.DS);
define('THEME_PATH',CONTENT.'themes'.DS.THEME_NAME.DS);
define('APP',ROOT.'Application'.DS);
define('CONTROL_PATH',APP.'contollers'.DS);
define('MODEL_PATH',APP.'models'.DS);
// index.php?p=admin&c=Goods&a=add
define("PLATFORM", isset($_REQUEST['p']) ? $_REQUEST['p'] : 'home');
define("CONTROLLER", isset($_REQUEST['c']) ? $_REQUEST['c'] : 'Index');
define("ACTION", isset($_REQUEST['a']) ? $_REQUEST['a'] : 'index');
unset($con);
}
// Autoloading
private static function autoload(){
$classname = algorithm_2_get_className();
if(substr($classname, -10) == "Controller"){
// Controller
$classFile = CONTROL_PATH . "{$classname}.php";
}else if (substr($classname, -5) == "Model"){
// Model
$classFile = MODEL_PATH . "{$classname}.php";
}
if(file_exists($classFile){
require_once $classFile;
}else{
// HANDLE FILE-NOT FOUND EXCEPTION...
}
}
// Routing and dispatching
private static function dispatch(){
// Instantiate the controller class and call its action method
$controller_name = CONTROLLER . "Controller";
$action_name = ACTION . "Action";
$controller = new $controller_name;
$controller->$action_name();
}
public function __construct($type, $args,$nature='show'){
/**
* var #type has two values = account | toDo
* var #type is post title
* var #nature is to determine the nature
*/
$this->args=$args;
$this->type=$type;
$this->nature=$nature;
self::route();
self::autoload();
self::dispatch();
}
}
my class structure is as followed:
myproject
|
-------src (namespace PicoCore;)
|
-----objects (namespace PicoCore\Objects;)
-----tests (namespace PicoCore\Tests;)
I've created composer.json from autoloading:
{
"autoload": {
"psr-0": {
"PicoCore": "src",
"PicoCore\\Objects" : "src/objects",
"PicoCore\\Tests" : "src/tests"
}
}
}
I've created a testing script after installing:
<?php
require_once "../../vendor/autoload.php";
use PicoCore\Objects\User;
$user = new User();
$user->name = "asaf";
echo $user->name;
?>
User Class:
<?php
/**
* Created by PhpStorm.
* User: avivpaz
* Date: 12/25/14
* Time: 12:07 PM
*/
namespace PicoCore\Objects;
class User extends APIUser implements ConvertibleObjects
{
/**
* #var string User's Name
*/
public $name;
/**
* #var string User's Push Id
*/
public $pushId;
/**
* #var UserDevice User's device type
*/
public $userDevice;
/**
* #var double The location latitude
*/
public $latitude;
/**
* #var double The location longitude
*/
public $longitude;
public function __construct()
{
$this->label = USER_LABEL;
}
/**
* init with APIUser
* #param $APIUser APIUser
* #return User type
*/
public static function withAPIUser($APIUser)
{
$user = new User();
$user->label=USER_LABEL;
$user->id = $APIUser->id;
$user->facebookAccessToken = $APIUser->facebookAccessToken;
$user->picoAccessToken = $APIUser->picoAccessToken;
$user->accessTokenExpires = $APIUser->accessTokenExpires;
return $user;
}
public function ConvertObjectToCypherSyntax()
{
return '{id:"' . $this->id . '",name:"' . $this->name . '",picoAccessToken:"' . $this->picoAccessToken . '",accessTokenExpires:"' . $this->accessTokenExpires->getTimestamp() . '",latitude:' . $this->latitude . ',longitude:' . $this->longitude . '}';
}
static public function ConvertNodeToObject($results)
{
$user = new User();
if (is_null($results))
return $user;
$user->id = $results->getProperty('id');
$user->name = $results->getProperty('name');
$user->picoAccessToken = $results->getProperty('picoAccessToken');
$user->latitude = $results->getProperty('latitude');
$user->longitude = $results->getProperty('longitude');
// $user->userDevice = UserDevice::ConvertNodeToObject($results['userDevice']);
if (!$results->getProperty('accessTokenExpires') == "")
$user->accessTokenExpires = getDateTimeFromTimeStamp($results->getProperty('accessTokenExpires'));
return $user;
}
static public function ConvertArrayToObject($array) {
$user = new User();
if (array_key_exists("id", $array))
$user->id = $array["id"];
if (array_key_exists("name", $array))
$user->name = $array["name"];
if (array_key_exists("pico_access_token", $array))
$user->picoAcceessToken = $array["pico_access_token"];
if (array_key_exists("access_token_expires", $array))
$user->accessTokenExpires = getDateTimeFromString($array["access_token_expires"]);
if (array_key_exists("device_type", $array))
$user->deviceType = $array["device_type"];
if (array_key_exists("latitude", $array))
$user->latitude = $array["latitude"];
if (array_key_exists("longitude", $array))
$user->longitude = $array["longitude"];
if (array_key_exists("userDevice", $array))
$user->userDevice = UserDevice::ConvertArrayToObject($array["userDevice"]);
return $user;
}
public function toArray()
{
$user = array();
if (!empty($this->id))
$user["id"] = $this->id;
if (!empty($this->name))
$user["name"] = urldecode($this->name);
if (!empty($this->picoAccessToken))
$user["pico_access_token"] = $this->picoAccessToken;
if (!empty($this->accessTokenExpires))
$user["access_token_expires"] = getMysqlDateTime($this->accessTokenExpires);
if (!empty($this->latitude))
$user["latitude"] = $this->latitude;
if (!empty($this->longitude))
$user["longitude"] = $this->longitude;
if (isset($this->userDevice)) {
$userDevice = $this->userDevice->toArray();
if (!empty($userDevice))
$user["userDevice"] = $userDevice;
}
if (count($user) > 0)
return $user;
return null;
}
}
I get a can't find class exception.. any ideas ?
With PSR-0
In order to use PSR-0, you need to change your structure layout to:
src/
└── PicoCore
├── Objects
│ └── User.php
└── Tests
And in your composer.json you need to add PicoCore namespace:
"psr-0": {
"PicoCore\\": "src"
}
Alternative with PSR-4
If you want to keep your current file system layout, you can use PSR-4 instead of PSR-0. In order to use PSR-4, you need to update composer.json:
"autoload": {
"psr-4": {
"PicoCore\\": "src",
"PicoCore\\Objects\\" : "src/objects",
"PicoCore\\Tests\\" : "src/tests"
}
}
After you made your changes, run composer dumpautoload to regenerate autoload files.
If it's a namespace without class, it's must finish with \\
So :
"autoload": {
"psr-0": {
"PicoCore\\": "src",
"PicoCore\\Objects\\" : "src/objects",
"PicoCore\\Tests\\" : "src/tests"
}
}
and check file autoload
composer/autoload_namespaces.php
see https://getcomposer.org/doc/04-schema.md#psr-0
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;
}