How to skip using __autoload? - php

I have a php file which has multiple classes in it. I noticed that __autoload is being called when I instantiate any of the classes, even after the 'package' file has been autoloaded. This is worrying me, because surely if the initial 'package' .php file has been loaded, it is unnecessary overhead for __autoload when the classes have already been loaded.
I probably made a hash of explaining that, so here is an example:
<?php
class Class1{};
class Class2{};
?>
Then in another file:
<?php
new Class1;
new Class2;
?>
__autoload will be used for both Class1 AND Class2's instantiation... even though they are housed in the same file.
Is there a way to get around this?
Sorry if my explanation isn't very good, I'd really appreciate any help or tips.

PHP's autoload should only be called if a class doesn't exist. In other words, for the most basic example, it uses the same logic as:
if( !class_exists("Class1") )
require "path\Class1.php";
If you are finding otherwise, I would check to be sure you are doing everything correctly and report a bug.
From PHP.net/autoload (important documentation highlighted):
In PHP 5, this is no longer necessary.
You may define an __autoload function
which is automatically called in case
you are trying to use a
class/interface which hasn't been
defined yet. By calling this
function the scripting engine is given
a last chance to load the class before
PHP fails with an error.
Bug in formatting, but the emphasis was on "which hasn't been defined yet". "Defined" occurs when a class is compiled (in most cases when a file containing said class is included).

__autoload is definitely NOT called the second time, when Class2 got defined as result of the first call.
First classes.php
<?php
class Class1 {};
class Class2 {};
Now test.php
<?php
function __autoload ($class)
{
print "Autoloading $class\n";
require 'classes.php';
}
$a = new Class1;
$b = new Class2;
print get_class($b);
When you run test.php, the result is:
Autoloading Class1
Class2
If you are getting different result, then there is something that you are not telling us.

Related

Is PHP 5's autoload inefficient?

When you manually include a PHP class you can do it while the current script is running, right? Then you can decide, if a condition matches you load it and if it doesn't you don't. Like this:
if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) {
include '../../../Whatever/SanitizeUserInput.class.php';
SanitizeUserInput::sanitize($_POST['someFieldName']);
}
But let's say I use the autoload feature with this class. Will it be effectively loaded at the beginning or will it be loaded only if it's used?
I mean, should I add the __autoload function only in classes that I'm 100% sure I'm going to use in any script (e.g. database connection, session management, etc.)?
Thanks
Autoload is called only when you are trying to access desired class. And it would be better to use spl_autoload_register() instead of __autoload
Documentation:
You may define an __autoload() function which is automatically called
in case you are trying to use a class/interface which hasn't been
defined yet.
and
spl_autoload_register() provides a more flexible alternative for
autoloading classes. For this reason, using __autoload() is
discouraged and may be deprecated or removed in the future.
Autoloading kicks in when you are trying to use a class that has not yet been loaded:
include 'foo.php';
new Foo; // autoload not used, because the class already exists
// Bar is not yet loaded here, auto or otherwise
new Bar; // Bar is being autoloaded, because it was not yet loaded
As such, autoloading can be very efficient. It's slightly less efficient than loading classes by hand at the time when you need them, because of the overhead of invoking the autoload function. But keeping track of loaded classes by hand is more work for very little return over autoload.
Try it out, you will see, that whenever PHP stumbles over a class it doesn't know yet, it will call your autoload function. When your autoload function tells PHP in which file the class is, it will load this file.
To make the answer short, PHP only loads the file when needed, that is true even for conditions, so following test class will never be loaded.
if (false)
{
$test = new CTest(); // never loaded with autoload.
}

PHP scope between two classes

I have a few files like below:
index.php:
require_once("foo.php");
require_once("bar.php");
foo.php:
class foo {
function1() {
}
}
bar.php:
class bar {
?????
}
My question is, is there any way of accessing function1 from the foo class in the bar class, without having to include the foo.php file in the bar.php file, as it has already been loaded in index.php?
Thanks in advance
When including a file, in PHP, you are not including anything into the current file, but into the current execution
Once a file has been included, it's content is known by the PHP interpreter -- and will remain known until the end of the execution of the current script.
It's a bit like copy-pasting : with your current index.php file, it's like if you had taken the code from foo.php and bar.php and copy-pasted into index.php.
So, yes, once foo.php has been loaded once, you can access what's defined by it from bar.php -- even if those two are included by index.php.
(What you means by access is a bit vague, though : you'll have to declare some methods as static, or instanciate the foo class, ... But all that will be possible from inside the body on a method declared in bar)
As a sidenote : you should be careful with your file inclusions : if you include twice a file that declares a class, for example, you'll get a fatal error, because it's forbidden to define two classes with the same name.
Remember the copy-pasting idea I wrote about earlier ? Includind a file twice, even from two distinct files, is like copy-pasting the same code twice...
To avoid that problem, we often use include_once which, as its name indicates, makes sure that a given file can only be included only once.
If foo.php has already been loaded, then the real question to ask yourself is, "Am I accessing function1() in a static or instance manner?"
If function1() is a static function (which in your example, is not):
class bar{
function function2(){
return foo::function1();
}
}
Otherwise, you will have to instantiate an instance of foo, making it a local- or class-scope variable, e.g.
class bar{
/*
* #var foo
*/
private $foo;
function __construct(){
$this->foo = new foo();
}
function function2(){
return $this->foo->function1();
}
}
Read this too: http://php.net/manual/en/language.oop5.static.php
By the way, like what Pascal MARTIN has explained, you do not need to do another include(), but usually for a large application, you will prefer auto-class-loading.
You should try to move away from including files manually, and instead work towards a solution where you can use autoloading.
Autoloading will allow you to lazy load, or only load the files that you need in each request - rather than making a spider web of included files.
You can do this either with __autoload or spl_autoload, read more on the subject here: http://php.net/manual/en/language.oop5.autoload.php
Small example of autoload below:
function __autoload($class_name) {
require_once $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
Using autoloading php can automatically try to load files when a class is not found, in this example there is no reason to include the class files for MyClass1 or MyClass2, php falls back to the __autoload function if it cannot find definitions for them.
Using this will mean you dont have to include either foo or bar in your examples, nor include them in index.php
You could do it statically, though there are limitations and this is an atrocious practice, since that function isn't actually static.
foo::function1();
The better approach would be to have the class bar take foo as a parameter. Depending on the uses, this could be done in the constructor or the particular method.

include files in a method?

i want to have a class that includes all files for me.
eg.
Loader::loadZend // loads all zend libraries
Loader::loadSymfony // loads all symfony components
if i include a file in a method, does this become globally available?
it seems that it doesnt work.
maybe i have done something wrong, or is there a workaround for this?
thanks
From http://uk.php.net/manual/en/function.include.php (emphasis mine)
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.
Having a loader that loads all classes of Zend, Symfony or whatever at once is a bad idea. Both have their own autoloader, so all you need to do is make the libraries available on the include path and then spl_autoload_register the framework's own autoloader.
If no global scope variables are defined, you should be fine. Otherwise, the globals will be lost.
For example,
a.php:
<?php
$a = "global a";
class c {
public $b = "member b";
}
?>
b.php
<?php
function inc() {
include 'a.php';
}
inc();
echo $a;
$class = new c;
echo $class->b;
?>
If you run b.php, you will find out $a is gone and class c or any function will still be available.
If you just include a class inside another class it is only available in the class you inserted the include.
So the solution is to create an autoloader that automaticly includes the classes needed on demmand. Here you have the info you need:
http://php.net/manual/es/language.oop5.autoload.php
It is basic programming for PHP5 OOP.
EDIT
Seeing your inquiry about a file. Neither. The file (to be processed via php functions) will only be available inside the function where it is called/used for, not globally in the whole application / website.

php require class call from inside method

from my understanding, require pastes code into the calling php file.
what if you were requiring from inside a method...it would paste the entire code/class inside the method, blocking the next statement in the method.
eg.
function test() {
require 'pathtosomeclasscode';
somestatement; // any code after the require is blocked.
}
how do i get around this, to be able to require code where-ever, without it being pasted in that exact spot?
Somewhat surprisingly, this appears to work just fine. The included code will execute inside the scope of Baz::bork() -- but the the code simply defines a class, and classes are global. So you end up with a defined class.
File: Foo.php:
<?PHP
class Foo{
function bar(){
echo "Hello from Foo::bar()!\n";
}
}
File: Baz.php:
<?PHP
class Baz{
function bork(){
require_once "Foo.php";
$f = new Foo();
$f->bar();
}
}
echo "testing internal definition:\n";
$b = new Baz();
$b->bork();
echo "\ntesting in global scope:\n";
$f = new Foo();
$f->bar();
echo "\nall done\n";
Output:
$ php Baz.php
testing internal definition:
Hello from Foo::bar()!
testing in global scope:
Hello from Foo::bar()!
all done
Now, I can't think of many places where you'd want to do things this way. People typically require_once() any possible dependencies at the top of their class file, outside of the class definition.
Calling require, require_once, include or include_once will not stop the execution of code within your function unless there is a problem with the included script. The code within the included file is executed in the same scope as the function (with defined functions and classes being global), not inserted into it, replacing what else is there.
The other answers recommend using one of alternatives to require as a solution -- these solutions may work for you if the error in your scripts is to do with a conflict in naming (i.e. an attempt at redefining a class or function), otherwise you may wish to give us more details of what has occurred (or not occurred) to make you think that there is a problem so that we can help you solve the real cause.
On a further note, these file inclusion methods do not paste code into your script. Pasting is a tool that people use to maintain text. I suggest that you read the PHP manual to try and further your understanding of how these functions work:
require
require_once
include
include_once
Post again if you've got further questions on their working after looking into them.
try require_once? Just incase your including it elsewhere.
If you use include_once('script.php') you won't run into errors about classes being redeclared.
I haven't tried the following myself, but I'm thinking this setup might also work if you don't want to include_once() redundantly:
class Whatever {
protected $classObject;
public function __construct( /*...*/ ) {
include('anotherClass.php');
$this->classObject = new anotherClass();
}
public function someFunction( /*...*/ ) {
$this->classObject->classObjectFunction();
}
public function anotherFunction( /*...*/ ) {
$this->classObject->classObjectFunction();
}
}
You could then call the following code which would each call a function in the same shared class object:
$Whatever = new Whatever();
$Whatever->someFunction();
$Whatever->anotherFunction();
I think what you're saying is that you don't want the code to execute right away. If that is correcty, you have several options:
You can move the require.
You can also read the file using fopen(), then parse it. (You can't call eval because it won't understand the HTML, but you can do it with a parser)
As I see, you're using external files for loading classes, am I correct? Why don't you use Autoloading Classes. I know it won't work when you want to load different class bodies in different circumstances, but I really don't know if it's a good practice.

Abstract a class away from PHP script?

Just wondering if there is anyway to have PHP just run a certain class given the name of the file (controller.php)?
I don't want to require, include or see any signs of it in the controller.php. I just want it to be there.
EDIT: Ok. What I mean by run is in some file hidden away from me I say something like... $class = new Class(); This way I can use $class in my controller.php
ALSO: I'm running PHP 5.3 - So I have namespaces and whatnot.
Anyway of doing this??
Thanks!
Matt Mueller
I'm going to take a big guess at what you really mean. I think you simply want to separate your class PHP file away from your main file without making any obvious includes.
If so, you might want to use the __autoload() function:
<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
This will notice that MyClass1 and MyClass2 haven't yet been defined and will call the autoload function with their class names as the parameter. So then MyClass1.php and MyClass2.php will be require_once'd.
You can autoload the Class file, you will still have to instantiate the Class by hand at some point. Or you will have to include a script that instantiates it for you. Or you re-architect your application so your actual script is included by another script, which pre-instantiates the Class for you.
In short: including the file can be automated, instantiating the Class not so much.

Categories