php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #61265 __autoload should know about traits
Submitted: 2012-03-03 13:10 UTC Modified: 2012-03-08 14:39 UTC
Votes:10
Avg. Score:4.3 ± 1.3
Reproduced:9 of 10 (90.0%)
Same Version:6 (66.7%)
Same OS:5 (55.6%)
From: manchokapitancho at gmail dot com Assigned:
Status: Open Package: Class/Object related
PHP Version: 5.4.0 OS:
Private report: No CVE-ID:
Have you experienced this issue?
Rate the importance of this bug to you:

 [2012-03-03 13:10 UTC] manchokapitancho at gmail dot com
Description:
------------
Currently, __autoload is automatically called when a class is not found. As of 
5.4.0, it is also called when a trait is not found. It is also called when an 
interface is not found.
Unfortunately, there is no way to understand what type of resource is being 
autoloaded.
So I suggest that a second optional argument is added to __autoload. It can 
receive three possible values from the PHP engine - for example:
AUTOLOAD_CLASS, AUTOLOAD_TRAIT and AUTOLOAD_INSTANCE.
This way, a better autoload handling can be achieved.


Patches

autoload.patch (last revision 2013-06-24 07:22 UTC) by jwalton at m3hc dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-03-04 17:11 UTC] gron@php.net
Could you elaborate a bit on the usecase?
Until now, there didn't seem to be the need to handle interfaces differently in an  
autoloader. Why would you treat traits differently from classes and interfaces?
 [2012-03-08 13:25 UTC] shiranai7 at hotmail dot com
It is now a critical feature but it would be nice. For example - if I decided to format the filenames depending on what is being autoloaded (class/interface/trait) I could not easily do it.

Adding a second argument to the autoload callback would make this possible and should not break anything.
 [2012-03-08 13:26 UTC] shiranai7 at hotmail dot com
Sorry.. it should say "It is NOT a critical feature" instead of "NOW".
 [2012-03-08 14:39 UTC] manchokapitancho at gmail dot com
Yes, there is a use case.
Currently, I use a workaround but in general, the idea behind is that after I 
locate the file, corresponding to the class name being autoloaded, 
I require_once the file and then check if the class is really inside 
(class_exists). As of 5.4, class_exists returns false for traits and I have to use 
class_exists || trait_exists. Not a big deal, really, but it is still possible to 
have different paths for classes (ex. /classes) and different one for traits 
(/traits).
 [2012-03-25 17:10 UTC] phristen at yahoo dot com
This would certainly be a nice feature.
However, keep in mind that it is not always possible to tell whether something is a class or an interface.
For example, when doing something like this, we can't tell whether 'A' is an interface or a class:

if ($a instanceof A) {

}
 [2012-03-26 03:42 UTC] phpmpan at mpan dot pl
`instanceof` operator does not trigget class loading:
-----------------------------------------
class X {}
function __autoload($name) {
    echo "Loading $name...\n";
}
$x = new X();
if ($x instanceof X) {
    echo 'x is X';
}
if ($x instanceof NonExistingClass) {
    echo 'blarg';
}
-----------------------------------------
The same applies to argument types.
 [2012-03-26 22:04 UTC] phristen at yahoo dot com
Ok, my point is still valid though.

Imagine I used is_a($a, "A", true) instead.
 [2013-06-24 07:22 UTC] jwalton at m3hc dot com
Actually, the ambiguous ones (i.e. is_a) do not call the autoload.
 [2013-06-24 07:28 UTC] jwalton at m3hc dot com
Added a patch, where autoloading will pass along the type its looking for.  Should be fixed to have constants, and a fix of err_012.phpt test should be fixed.  Quick and dirty though, and I'll clean it up if someone wants it.

function __AUTOLOAD($typename, $type) {

}
or you can use spl as well spl_autoload_register();

$type = 0, Class
$type = 1, Interface
$type = 2, Trait

class Test extends Test2 {};  $type = 0 for loading Test2
class Test implements Test2 {}; $type = 1 for loading Test2
class Test { use Test2; }; $type = 2 for loading Test2
class_exists("A"); $type = 0 for loading A
interface_exists("A"); $type = 1 for loading A
trait_exists("A"); $type = 2 for loading A

This patch is for php-5.5.0 release.
 [2013-06-24 17:23 UTC] jwalton at m3hc dot com
$extension = array(".pclass", ".pinterface", ".ptrait");
spl_autoload_register(function($classname, $type) {
  global $includepath;
  if( $type >=0 && $type <= 2 ) {
    $filename = "$includepath/".strtolower($classname).$extension[$type];
    if( is_readable($filename) ) {
      include_once($filename);
    }
  }
});

You could also use spl_autoload_extensions(".pclass,.pinterface,.ptrait") or

spl_autoload_register(function($classname, $type) {
  global $includepath;
  $filename = "$includepath/".strtolower($classname);
  if( is_readable("$filename.pclass" ) {
    include_once("$filename.pclass");
  } else if( is_readable("$filename.pinterface") ) {
    include_once("$filename.pinterface");
  } else if( is_readable("$filename.ptrait") ) {
    include_once("$filename.ptrait");
  }
});

This will make zero difference if all your files are classes (type doesn't mean anything, but its about 20-30% more efficient when you start including interfaces and traits, because there are now less stat calls being done on the filesystem.  This code allows for only one stat needed per call, instead of 1-3.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sun Apr 20 01:02:05 2014 UTC