I'm currently making my first website with PHP. Rather than writing autoload for each individual page, I wish to create one file with a general autoload ability.
Here is my autoloadControl.php:
// nullify any existing autoloads
spl_autoload_register(null,false);
//specify extensions that may be loaded
spl_autoload_extensions('.php. .class.php');
function regularLoader($className){
$file = $className.'.php';
include $file;
}
//register the loader function
spl_autoload_register('regularLoader');
Here is my index.php file:
require("header.php");
require("autoloadControl.php");
$dbConnection = new dbControl();
$row=$dbConnection->getLatestEntry();
Currently, the $dbConnection = new dbControl() gives me the following error:
Fatal error: Class 'dbControl'
So my question is, is there a way to use autoload this way or must I place it at the top of every PHP file I write that uses another file?
Placing spl_autoload in an external file is both valid and a good practice for making your code more maintainable--change in one place what could be 10, 20, or more.
It appears that your dbControl class is not being provided in the code you provided. Assuming you are including the class before referencing it, and the class works properly, then you should have no problem accomplishing this task.
require("header.php");
require("autoloadControl.php");
$dbConnection = new dbControl(); // Where is this class located?
Here is an OOP approach for your autoloadControl.php file:
<?php
class Loader
{
public static function registerAutoload()
{
return spl_autoload_register(array(__CLASS__, 'includeClass'));
}
public static function unregisterAutoload()
{
return spl_autoload_unregister(array(__CLASS__, 'includeClass'));
}
public static function registerExtensions()
{
return spl_autoload_extensions('.php. .class.php');
}
public static function includeClass($class)
{
require(PATH . '/' . strtr($class, '_\\', '//') . '.php');
}
}
?>
Your problem is not related to where you are defining your callback, but how.
Using spl_autoload_extensions('.php') would achieve the same thing as your custom callback; you don't need both if your callback is as simple as this. Your comment is also wrong - calling spl_autoload_register with no arguments will not clear current callbacks, but it will register the default callback.
However, in your code, you have specified the argument to spl_autoload_extensions incorrectly - it should be a comma-separated list of extensions. So I think what you want is this:
// Tell default autoloader to look for class_name.php and class_name.class.php
spl_autoload_extensions('.php,.class.php')
// Register default autoloader
spl_autoload_register();
// READY!
The main difference this will make from your code is that the default autoloader will look for 'dbcontrol.php' (all lower-case) whereas yours will look for 'dbControl.php' (case as mentioned in PHP code). Either way, you certainly don't need both.
Related
I want to create a number of functions in my plugin 'membershipintegration.php' which can be called anywhere on my Wordpress site.
I thought that if I created a class and defined a public function within the class in the membershipintegration.php I could use it wherever I liked.
class MembershipIntegration
{
public function switchmembership () {
echo 'some code'
}
}
However, it doesn't seem to work and I've used 'function_exists' on my sandbox page and it says the function isn't active.
Any thoughts much appreciated. Thank you.
Wordpress automatically load your membershipintegration.php when the plugin is active, then any function created inside this file or any other included file is automatically loaded and available in any place.
The recommendation is:
Create a file called functions.php
<?php
function myFunctionOne(){
//some code
}
and then in your membershipintegration.php use:
require __DIR__.DIRECTORY_SEPARATOR.'functions.php';
There's no such thing as a function inside a class. PHP classes consist of properties and methods. The keyword to define a user-defined method is function so it's a little confusing.
To access a public method, you first need an instance of that method. For instance:
$s = new MembershipIntegration();
Then you can access the public method:
$s->switchmembership();
<?php
require plugin_dir_path( __FILE__ ) . 'file-name.php';
new CLassName();
?>
put this code on your plugin index file then it can be call any where if your plugin is activate
I am using Drupal 7 and I am using my custom module's .info file along with the "files[] = ...." directive to allow autoloading of my classes when required. Each class only contains static public functions and everything is working nicely when these functions are called from a function of the general scope.
Working example:
If I go to /devel/php and call the function ClassTwo::getValue() everything is executed without error.
Example with error:
If I call the function ClassTwo::getValue() from within another autoloaded function ClassOne::generate() an exception is thrown that the class ClassTwo() doesn't exist. The error is solved if I specifically include the file containing the class ClassTwo.
I don't believe it has something to do with Drupal's autoloading mechanism though. Is my scenario allowed in PHP 5.3?
For better clarification I have added below example code. That's the nearest I can provide to working code.
mymodule/mymodule.info
name = "MyModule"
core = "7.x"
files[] = "includes/plugins/ClassOne.inc"
files[] = "includes/plugins/ClassTwo.inc"
mymodule/mymodule.module
function mymodule_page_callback() {
return ClassOne::generate();
}
mymodule/includes/plugins/ClassOne.inc
Class ClassOne {
static public function generate() {
$value = ClassTwo::getValue();
// Process $value
return $value;
}
}
mymodule/includes/plugins/ClassTwo.inc
Class ClassTwo {
static public function getValue() {
// Somehow retrieve the value.
return $value;
}
}
UPDATE: Using Drupal's xautoload module with PSR-4 everything works incredibly fine and I have turned to this method as a solution. If anyone has an answer though, other than PSR-0/PSR-4, I would like to know it.
I am working on replacing some old objects with updated ones in php. The site currently has an __autoload function that simply calls a .inc file in the include directory. I have created a new autoload function for the updated objects using spl_autoload_register. It uses a directory named lib and namespaces.
I have an object named Sample, and the old object, also named Sample, references a definition in include/sample.inc. Then new object path is lib/Sample.php. My problem is, even though I am using the spl_autoload_register on the page that is calling the object, it is still calling the old object. Here is my code (please note that the __autoload() is defined prior to reaching this page).
<?php
spl_autoload_register('autoload_lib');
$sample_id = req('sample_id');
$alert = req('alert');
if (!empty($sample_id))
{
$sample = new Sample($sample_id);
var_dump($sample); die();
$referral = $sample->Referral();
matry::open (get_defined_vars());
}
else
{
matry::open(get_defined_vars());
}
When you start using spl_... methods, they usurp any existing __autoload function:
If your code has an existing __autoload() function then this function
must be explicitly registered on the __autoload stack. This is because
spl_autoload_register() will effectively replace the engine cache for
the __autoload() function by either spl_autoload() or
spl_autoload_call().
One can see this in a simple example:
<?php
ini_set('display_errors', 1);
function __autoload($className) {
exit("__autoload");
}
spl_autoload_register(function($className) {
exit("spl_autoload");
});
// try to create nonexistent class
new Foo();
?>
The above example outputs "spl_autoload"
Are you sure no other autoloader has been registered at that stage in the script? You could test this by adding the prepend argument (e.g., spl_autoload_register('autoload_lib', true, true); Is autoload_lib callable at that time in the script (has it's source been included?)
I am learning how to use namespaces and autoloading in PHP today, and I appear to have hit a roadblock. Things seem to work when I don't use spl_autoload_register but instead require_once.
My folder structure is bare minimal:
- index.php
- class/
- Users.php
In my index.php file I have:
<?php
require_once('class/Users.php');
echo User::get(1);
In my class/Users.php file I have:
<?php
Class User {
function get($id) {
return $id;
}
}
and this works absolutely fine, returning the ID of 1
Ideally I will want to use an Autoload function and I discovered spl_autoload_* and this is what I tried to do, but with no success:
In my class/Users.php file I have:
<?php
namespace Users; // Added a namespace
Class User {
function get($id) {
return $id;
}
}
In my index.php file I have:
<?php
// Changed to using spl_autoload_register using an anonymous function to load the class
spl_autoload_register(function($class){
include('class/' . $class . '.php');
});
echo Users\User::get(1); // Added the Users namespace
but I get an error:
`Class 'Users\User' not found in /Applications/MAMP/htdocs/index.php on line 7`
Not really sure what I'm doing wrong.
I think you should add \ infront of the namespace path.
Example
\Users\User::get(1);
If you have to use a base path, like Traversable() you would also need to do
new \Traversable()
The autoloader is called with the full class name as an argument, including the namespace. In your example this is Users\User, so you end up doing
include('class/Users\User.php');
This fails because the class definition is not in a directory named Users (by the way, include would emit a warning that it cannot find the file which includes the expanded filename, and this warning would make things clearer -- do you have disabled error reporting?)
It's a probably a good idea to have the autoloader fail on the spot when the file is not found so that the failure mode is more apparent. For example you could change it to
require('class/' . $class . '.php'); // require will end the script if file not found
or to something like
$result = #include('class/' . $class . '.php'); // see documentation for include
if ($result === false) {
die("Could not include: 'class/$class.php'");
}
i'm having trouble with a redeclare error. I can't find a fix for it yet, but basically:
I have 2 files that are modules and they use the same function names like install(), uninstall() etc etc which are used by the system.
When I include both the files at the same time for gathering data, I get a redeclare error. I want it so that I can include both and when the next file is loaded, it just rewrites over the previous function.
Or is there a way I can unset or clear the function? I've tried include, require, require_once etc... No work :(
In PHP it is not possible to overwrite a function that you have previously defined.
So the modules stand in each others way and one module prevents the other from working.
Actually Modules need to make use of the same named functions while they must be able to co-exist next to each other.
That can be done by moving the modules code into classes of their own. One module is one class then.
You can then define an interface with the functions your module classes must provide. As Modules therefore must have a streamlined interface - each module has a install() and uninstall() function for example - just define an object interface at first specifying those needed module functions:
module_definitions.php
interface Module {
public function install();
public function uninstall();
}
mod_Module1.php:
class Module1 implements Module {
public function install() {...}
public function uninstall() {...}
}
mod_Module2.php:
class Module2 implements Module {
public function install() {...}
public function uninstall() {...}
}
After doing so, whenever one of your routines needs to deal with any module, you can make that function require a module:
function module_install(Module $module) {
$module->install();
}
This function will only accept an existing module as a parameter. So you can not use your standard require/include for this but modules need to be instantiated prior use. You can put that into a module loader function as well:
function module_require($moduleName) {
$class = $moduleName;
if (!class_exists($class) {
$file = sprintf('mod_%s.php', $moduleName);
require $file;
if (!class_exists($class)) {
throw new DomainException(sprintf('Invalid Module File %s for Module %s.', $file, $moduleName));
}
}
}
How to access the modules functions then?
The only thing left is now to access the actual module.
You could the create a global array variable containing all modules:
// Define existing modules
$modules = array('Module1', 'Module2');
// Require the modules
array_map('module_require', $modules);
// instantiate each module:
$moduleInstances = array_map(function($module){return new $module;}, $modules);
// map modules name (key) to it's module instance:
$modules = array_combine($modules, $moduleInstances);
// access module by name:
$modules['Module1]->install();
However this has some problems. All modules need to be loaded at once for example, but you might not need to use all modules. Or imagine you would overwrite the global $modules array, all modules would be lost.
To prevent all that and allow more control and easier access to the modules, this can be put into a class of it's own that will take care of all the details. Like a register that knows which modules are loaded or not, registers them as needed.
For the following I assume a module can only exists once. If an object can only exist once this is often called a Singleton. So we'll wrap the management of loading and providing the module by it's name into a class of it's own that deals with the details:
class Modules {
private $modules = array();
private static $instance;
// singleton implementation for Modules manager
private static function getInstance() {
if (null === Modules::$instance) {
Modules::$instance = new Modules;
}
return Modules::$instance;
}
// singleton-like implementation for each Module
public function get($moduleName) {
if (!isset($this->modules[$moduleName]) {
module_require($moduleName);
$newModule = new $moduleName();
if (! $newModule instanceof Module) {
throw new DomainException(sprintf('Not a Module: %s', $moduleName));
}
$this->modules[$moduleName] = $newModule;
}
return $this->modules[$moduleName];
}
// get a module by name
public static function get($moduleName) {
return Modules::getInstance()->get($moduleName);
}
}
Put this class into module_definitions.php as well, which should be always included in your application.
So whenever you need to access a module you can do now by using the static get function with the name of the module:
Modules::get('Module1')->install();
Modules::get('Module2')->install();
No. You have a application design problem.
Rename the second function and call it on the locations you want the second to be used.
You cannot have two functions with the same name in the same scope.
If you have php5.3 or above, namespaces can be the answer: each plugin has its own, so the functions became
\plugin1\install()
\plugin2\install()
et cetera.
You may also wish to create unique classes inside these include files, then have them extend a generic class and use that generic class as a type to anchor to when you want to call up these functions at a higher level. You could also have one overload the other and then when you execute a method in one, it could be passed right on to the next.
Theoretically if you wrap the functions of each file in a separate class then you can call them both without problems. You don't even need to really worry about class state if you call them statically.
You cant use two time the same function name in the same namespace.
You should rename your second function or use namespaces like "Maerlyn" suggest
This problem can be solved by namespaces or/and static class.
Easiest way is to wrap these functions in class with static methods.
After that you'll be able not only to include them both, but also to use autoload-functions and forget about 'include'.
class Class1
{
public static function install()
{}
}
class Class2
{
public static function install()
{}
}
More about namespaces and autoload