I'm developing a website for my project.
My folder structure looks like this:
/testingSite
/src
/WordBreaker.php
/index.php
I have a problem when using a function in WordBreaker.php
Here is how the function is defined in WordBreaker.php
<?php
class WordBreaker
{
function breakIntoWords($text)
{
$ranges = $this->breakIntoRanges($text);
$textList = $this->rangesToTextList($text, $ranges);
return $textList;
}
}
?>
And here is where I want to use a function (in index.php)
<?php
include "src/WordBreaker.php";
$instance = new WordBreaker ();
if ( isset( $_POST['btnSubmit'] ) ) {
$result = $instance->breakIntoWords($input);
}
?>
When I test the site, the error occur
Fatal error: Class 'WordBreaker' not found in C:\xampp\htdocs\testingSite\index.php on line 4
What should I do?
Use require_once instead of include
<?php
require_once("src/WordBreaker.php");
$instance = new WordBreaker ();
if ( isset( $_POST['btnSubmit'] ) ) {
$result = $instance->breakIntoWords($input);
}
?>
or you can add an autoloader function
<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}
$vars = new IUarts();
print($vars->data);
?>
You can include it using DIR
require __DIR__."/src/WordBreaker.php";
$instance = new WordBreaker();
_ DIR _ is 'magical' and returns the directory of the current file without the trailing slash.
" If used inside an include, the directory of the included file is returned. This is equivalent to dirname(_ FILE _). This directory name does not have a trailing slash unless it is the root directory."
Related
I'm trying to use the SPL autoloader in php 8.1 but getting the bellow error.
PHP Parse error: syntax error, unexpected identifier "Router", expecting "{" in index.php on line 54
I have tested this in similar environments but on different versions of php and less than 8.1 all run perfectly fine. So the issue is unique to 8.1.
I can't seem to find anything other than the old autoloader function being depreciated on the docs which was to be replaced with spl.
I can't help but feel it's a syntax error specific to 8.1 and not actually anything to do with the spl autoloader. But again I've tried various things and just can't seem to get to the bottom of it.
Doe's anyone know of a specific reason why this may be happening?
Bellow is the code I'm using. Which again works in less than 8.
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
class Init {
function __construct() {
define( 'APPS_PATH', dirname( __FILE__ ) . '/' );
// Get params
$this->page = (isset($_GET['page'])) ? $_GET['page'] : 'Home';
$this->action = (isset($_GET['page'])) ? $_GET['action'] : false;
}
public function get_page(){
return $this->page;
}
public function get_action(){
return $this->action;
}
public static function register() {
spl_autoload_register( function ( $class ) {
$class = str_replace( '\\', '/', $class );
$class = str_replace( '/\s+/', '', $class );
$file = APPS_PATH . $class . '.php';
if ( file_exists( $file ) ) {
// Check for Clas Introduction : echo '['.$file.']'.PHP_EOL;
require_once ( $file );
return true;
}
return false;
} );
}
}
$init = new Init();
$init->register();
// Routing to operation
use routing\ Router as Router;
$router = new Router();
$router->go_to_page($init->get_page());
You have extra space here:
use routing\ Router as Router;
It should be:
use routing\Router as Router;
This is a change in PHP 8 syntax:
Namespaced names can no longer contain whitespace: While Foo\Bar will be recognized as a namespaced name, Foo \ Bar will not. Conversely, reserved keywords are now permitted as namespace segments, which may also change the interpretation of code: new\x is now the same as constant('new\x'), not new \x().
(ref)
When I use require_once or include_once to include a file it does not work, while when I use require or include it works fine.
public function ParseURL() {
require_once (APP_PATH . "config/config.php");
$this->url_as_parts = explode('/', $this->url);
$class = isset($this->url_as_parts[0]) ? $this->url_as_parts[0] : $config['default_controller'];
$method = isset($this->url_as_parts[1]) ? $this->url_as_parts[1] : "index";
$parms = isset($this->url_as_parts[2]) ? $this->url_as_parts[2] : "";
if (!class_exists($class)) {
trigger_error("The class {$class} not exists <br/>");
exit;
}
$controller = Object::get($class);
if (!method_exists($controller, $method)) {
header('HTTP/1.0 404 Not Found');
include(SYSTEM_PATH . "languages/" . $config['system_language'] . "/errors/404_not_found.html");
exit;
}
if (empty($parms)) {
$controller->{$method}();
} else {
$parms_array = array_slice($this->url_as_parts, 2);
call_user_func_array(array($controller, $method), $parms_array);
}
}
The following line does not produce an error and the path is correct
require_once (APP_PATH . "config/config.php"); but I cant access $config['system_language'] which is inside the file config.php.
Note that when I change the require_once to require or include, everything is OK.
As comes from require_once description - file required only once
Any other require_once of this file will not work.
And you obviously run you function ParseURL more than once. So, your require_once not working on second and consecutive calls.
So, you can use just require or, as I see this is part of a class, create, for example, a wrapper method which will assign config data to your class variable. I.e:
public function getConfig()
{
$this->config = require_once('FILE');
}
In this case your config file should return array or object of config variables.
Can it be that something else includes config/config.php, and then redefines/overwrites the variable $config?
The difference between require_once() and is regular counterparts (include() etc) is that require_once() only includes (and executes, if applicable) something if it hasn't been included before.
This might be because you are already loading config/config.php somewhere before in your code.
Calling require_once(APP_PATH . "config/config.php"); checks that the file config.php already is included and hence does not include it inside that function.
That is the reason your function does not have access to $config variable.
Hope that helps.
Can I set it as a global variable like:
<?php
$GLOBALS['dbconnect'] = require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR.'/location/file.php');
$short = $GLOBALS['dbconnect'];
function someFunction() {
echo $short;
}
?>
I am using a database connection file twice, once outside of a function, and once inside a function. The query inside the function can't run because the credentials, servername, db, etc.. are not defined.
I'm not sure how this works?
When I place the require_once file inside the brackets, nothing happens, page is white.
This is the first example from link
<?php
function __autoload($class_name) {
include $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
If you don't want to use an auto loader for whatever reason you can do the following. Have a file called config.php at the root of your project and have it contain this code.
<?php
// Replaced the \ which appear on localhost to / so it works online.
define("BASE_DIR", str_replace("\\", "/", __DIR__));
$files = [
BASE_DIR . "/path/to/my/file.php"
];
function loadFiles()
{
foreach ($files as $file) {
require_once $file;
}
}
?>
Then in your other files include the config file and call loadFiles. This is essentially an autoloader but sometimes it can be hard to grasp so you can use this.
How can I check if a class exists already in a folder then do not load this class again from another folder?
I have this folder structure for instance,
index.php
code/
local/
And I have these two identical classes in code/ and local/
from local/
class Article
{
public function getArticle()
{
echo 'class from local';
}
}
from core,
class Article
{
public function getArticle()
{
echo 'class from core';
}
}
So I need a script that can detects the class of Article in local/ - if it exits already in that folder than don't load the class again from core/ folder. Is it possible?
This is my autoload function in index.php for loading classes,
define ('WEBSITE_DOCROOT', str_replace('\\', '/', dirname(__FILE__)).'/');
function autoloadMultipleDirectory($class_name)
{
// List all the class directories in the array.
$main_directories = array(
'core/',
'local/'
);
// Set other vars and arrays.
$sub_directories = array();
// When you use namespace in a class, you get something like this when you auto load that class \foo\tidy.
// So use explode to split the string and then get the last item in the exloded array.
$parts = explode('\\', $class_name);
// Set the class file name.
$file_name = end($parts).'.php';
// List any sub dirs in the main dirs above and store them in an array.
foreach($main_directories as $path_directory)
{
$iterator = new RecursiveIteratorIterator
(
new RecursiveDirectoryIterator(WEBSITE_DOCROOT.$path_directory), // Must use absolute path to get the files when ajax is used.
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $fileObject)
{
if ($fileObject->isDir())
{
// Replace any backslash to '/'.
$pathnameReplace = str_replace('\\', '/', $fileObject->getPathname());
//print_r($pathnameReplace);
// Explode the folder path.
$array = explode("/",$pathnameReplace);
// Get the actual folder.
$folder = end($array);
//print_r($folder);
// Stop proccessing if the folder is a dot or double dots.
if($folder === '.' || $folder === '..') {continue;}
//var_dump($fileObject->getPathname());
// Must trim off the WEBSITE_DOCROOT.
$sub_directories[] = preg_replace('~.*?(?=core|local)~i', '', str_replace('\\', '/', $fileObject->getPathname())) .'/';
}
}
}
// Mearge the main dirs with any sub dirs in them.
$merged_directories = array_merge($main_directories,$sub_directories);
// Loop the merge array and include the classes in them.
foreach($merged_directories as $path_directory)
{
if(file_exists(WEBSITE_DOCROOT.$path_directory.$file_name))
{
// There is no need to use include/require_once. Autoload is a fallback when the system can't find the class you are instantiating.
// If you've already included it once via an autoload then the system knows about it and won't run your autoload method again anyway.
// So, just use the regular include/require - they are faster.
include WEBSITE_DOCROOT.$path_directory.$file_name;
}
}
}
// Register all the classes.
spl_autoload_register('autoloadMultipleDirectory');
$article = new Article();
echo $article->getArticle();
of course I get this error,
Fatal error: Cannot redeclare class Article in C:\wamp\...\local\Article.php on line 3
class_exists seems to be the answer I should look into, but how can I use it with the function above, especially with spl_autoload_register. Or if you have any better ideas?
Okay, I misunderstood your question. This should do the trick.
<?php
function __autoload($class_name) {
static $core = WEBSITE_DOCROOT . DIRECTORY_SEPARATOR . "core";
static $local = WEBSITE_DOCROOT . DIRECTORY_SEPARATOR . "local";
$file_name = strtr($class_name, "\\", DIRECTORY_SEPARATOR):
$file_local = "{$local}{$file_name}.php";
require is_file($file_local) ? $file_local : "{$core}{$file_name}.php";
}
This is easily solved by using namespaces.
Your core file goes to /Core/Article.php:
namespace Core;
class Article {}
Your local file goes to /Local/Article.php:
namespace Local;
class Article {}
And then use a very simple autoloader, e.g.:
function __autoload($class_name) {
$file_name = strtr($class_name, "\\", DIRECTORY_SEPARATOR);
require "/var/www{$file_name}.php";
}
PHP loads your classes on demand, there's no need to load the files up front!
If you want to use an article simply do:
<?php
$coreArticle = new \Core\Article();
$localArticle = new \Local\Article();
Sometime I have to use include_once and include it depend how the page are accessed. For example:
sales.php
include("class/pdoDatabase.php");
include("class/ClassExample.php");
$obj = new ClassExample();
$obj->getNewItem(1);
ClassExample.php
include_once("class/pdoDatabase.php");
class ClassExample {
public function getNewItem($id) { .. }
public function addNew($id) { .. }
}
// Accessing this file directly via Ajax request
if (isset($_POST['AddNew'])) {
$obj = new ClassExample ();
$obj->addNew($_POST['id']);
}
}
If you access to sales.php which will then load include("class/ClassExample.php");, however I have to use include_once in the ClassExample.php because pdoDatabase.php might be already loaded in sales.php.
If you access the file directly to ClassExample.php with POST query, it mean it will have to load the file and create an object.
Problem:
Problem is when you access to ClassExample.php directly - it could not find class/pdoDatabase.php . It work fine when sales.php load class/pdoDatabase.php file
This is not a problem with include_once and include difference. This is a problem with relative paths. Include always uses paths relative to called php file. You have this file structure:
sales.php
[class]
- pdoDatabase.php
- ClassExample.php
when you call sales.php everything is ok, but when you call ClassExample.php it's trying to find class/class/pdoDatabase.php which don't exist.
Change include line in your ClassExample.php
include_once(dirname(__FILE__)."/pdoDatabase.php");
and use the same pattern everywhere.
You are doing it wrong.
Instead of manually loading each class file, you should be using autoloader, that you initialize in bootstrap stage of your application. Something along the lines of:
$root = __DIR__;
spl_autoload_register(function( $className ) use ( $root ){
$className = str_replace( '\\', '/', $className );
$filepath = $root . '/' . strtolower( $className ) . '.php';
if ( !file_exists($filepath) )
{
return false;
}
require $filepath;
return true;
});
To learn more about this, please read about spl_autoload_register() in the manual.