I have asked a similar question to this one already but I think it was badly worded and confusing so hopefully I can make it a bit clearer.
I am programming in a native Linux file system.
I have a class of HelpTopic:
class HelpTopic extends Help{}
And a class of Help:
class Help{}
Now I go to include HelpTopic:
include('HelpTopic.php');
And even though I do not instantiate HelpTopic with new HelpTopic() PHP (in a Linux file system) still reads the class signature and tries to load Help with HelpTopic.
I do not get this behaviour from a cifs file system shared from a Windows System.
My best guess is that there is some oddity with Linux that causes PHP to react this way but not sure what.
Does anyone have any ideas or solutions to this problem?
EDIT:
I have added my loading function to show what I am doing:
public static function import($cName, $cPath = null){
if(substr($cName, -2) == "/*"){
$d_name = ROOT.'/'.substr($cName, 0, -2);
$d_files = getDirectoryFileList($d_name, array("\.php")); // Currently only accepts .php
foreach($d_files as $file){
glue::import(substr($file, 0, strrpos($file, '.')), substr($cName, 0, -2).'/'.$file);
}
}else{
if(!$cPath) $cPath = self::$_classMapper[$cName];
if(!isset(self::$_classLoaded[$cName])){
self::$_classLoaded[$cName] = true;
if($cPath[0] == "/" || preg_match("/^application/i", $cPath) > 0 || preg_match("/^glue/i", $cPath) > 0){
return include ROOT.'/'.$cPath;
}else{
return include $cPath;
}
}
return true;
}
}
I call this by doing glue::inmport('application/models/*'); and it goes through including all the models in my app. Thing is PHP on a linux based file system (not on cifs) is trying to load the parents of my classes without instantiation.
This is a pretty base function that exists in most frameworks (in fact most of this code is based off of yiis version) so I am confused why others have not run into this problem.
And even though I do not instantiate HelpTopic with new HelpTopic() PHP still reads the class signature and tries to load Help with HelpTopic.
Correct.
In order to know how to properly define a class, PHP needs to resolve any parent classes (all the way up) and any interfaces. This is done when the class is defined, not when the class is used.
You should probably review the PHP documentation on inheritance, which includes a note explaining this behavior:
Unless autoloading is used, then classes must be defined before they are used. If a class extends another, then the parent class must be declared before the child class structure. This rule applies to class that inherit other classes and interfaces.
There are two ways to resolve this problem.
First, add a require_once at the top of the file that defines the child class that includes the file defining the parent class. This is the most simple and straight-forward way, unless you have an autoloader.
The second way is to defione an autoloader. This is also covered in the documentation.
The ... thing ... you're using there is not an autoloader. In fact, it's a horrible abomination that you should purge from your codebase. It's a performance sap and you should not be using it. It also happens to be the thing at fault.
We don't have the definition of getDirectoryFileList() here, so I'll assume it uses either glob() or a DirectoryIterator. This is the source of your problem. You're getting the file list in an undefined order. Or, rather, in whatever order the underlying filesystem wants to give to you. On one machine, the filesystem is probably giving you Help.php before HelpTopic.php, while on the other machine, HelpTopic.php is seen first.
At first glance, you might think this is fixable with a simple sort, but it's not. What happens if you create a Zebra class, and then later need to create an AlbinoZebra that inherits from it? No amount of directory sorting is going to satisfy both the "load ASCIIbetical" and the "I need the Zebra to be first" requirements.
Let's also touch on the performance aspect of the problem. On every single request, you're opening a directory and reading the list of files. That's one hell of a lot of stat calls. This is slow. Very slow. Then, one by one, regardless of whether or not you'll need them, you're including the files. This means that PHP has to compile and interpret every single one of them. If you aren't using a bytecode cache, this is going to utterly destroy performance if the number of files there ever grows to a non-trivial number.
A properly constructed autoloader will entirely mitigate this problem. Autoloaders run on demand, meaning that they'll never attempt to include a file before it's actually needed. Good-performing autoloaders will know where the class file lives based on the name alone. In modern PHP, it's accepted practice to name your classes such that they'll be found easily by an autoloader, using either namespaces or underscores -- or both -- to map directory separators. (Meaning namespace \Models; class Help or class Models_Help would live in Models/Help.php)
Unfortunately most examples won't be useful here, as I don't know what kind of weird things your custom framework does. Take a peek at the Zend Framework autoloader, which uses prefix registration to point class prefixes (Model_) at directories.
Related
I've come across an unusual class loading problem in PHPUnit, initially experienced with 4.3.5 and now latest 4.4.2 as well (latest stable).
I have a bootstrap file which is loaded via a phpunit.xml automatically, which includes Composer's default autoloader and also my own autoloader. This works fine as it is. However, I discover that if I load a test class in the bootstrap, then PHPUnit isn't able to resolve the class name correctly, and it thus does not load.
I get this error:
Class 'test/unit/tests/UpdateAllTest' could not be found in '/full/project/path/webapp/test/unit/tests/UpdateAllTest.php'.
(My purpose in wanting to refer to a test class in the bootstrap is to add a database build method in each one, keeping it with the test file it pertains to. I plan to do this in the bootstrap rather than a setUp() method, as I want it to run once across all tests, not once per test method).
I've done a bit of light debugging inside PHPUnit itself (in particular PHPUnit_Runner_StandardTestSuiteLoader::load) and found the class name is incorrectly supplied as a path and not as a namespaced class name. Here is the relevant clause:
if (class_exists($suiteClassName, false)) {
$class = new ReflectionClass($suiteClassName);
if ($class->getFileName() == realpath($suiteClassFile)) {
return $class;
}
}
The value of $suiteClassName is test/unit/tests/UpdateAllTest, which is plainly not a namespaced anything - it should be Awooga\Testing\Unit\UpdateAllTest, something that is normally handled by a custom mapping in my autoloader.
I don't think I am doing anything particularly unusual with PHPUnit, and so find it unlikely that this is a bug that no-one else has thus far experienced. In these circumstances, do I maybe need to declare the class namespaces in the phpunit.xml or something unusual like that? Grasping at straws here!
Any thoughts as to what the cause of this seemingly trivial problem could be would be appreciated. In the meantime I will just move these set-up methods to a different file/class - not ideal but not the end of the world either. I'm on PHP 5.5.x and Ubuntu 12.04.
I haven't fixed this, but my build methods are now so long that it makes sense for them to appear in different classes anyway. I have a naming convention so that a test of *Test.php has a corresponding build class of *Build.php.
I use PHPUnit's bootstrap system to scan for build classes and to call a static build() within automatically.
Maybe you are also experiencing this problem.
Having the path as parameter is normal behavior at this point, check further down in PHPUnit_Runner_StandardTestSuiteLoader::load causes this confusing error message.
We have a standard in use, where we create exceptions within the main class for returning errors etc... The problem is, that all the standard sniffs do not like this. We are writing our own sniffs then for this, but thought I would inquire why this was not desirable?
For instance, we have:
<?php
class FOO_EXCEPTION extends Exception { }
class FOO_EXCEPTION_BAR extends FOO_EXCEPTION { }
class FOO_EXCEPTION_POLE extends FOO_EXCEPTION { }
class FOO
{
public function MethodDoingSomething()
{
if('some condition happens') {
throw new FOO_EXCEPTION_BAR();
}
if('some other condition') {
throw new FOO_EXCEPTION_POLE();
}
...
}
}
?>
This allows our code to return different exceptions to indicate what happened to the caller, but if a dedicated try/catch is not available, the basic Exception may still be caught.
This comes in handy when working with databases or other external objects, since the nature of the error may be returned to a component higher up the call stack to handle the error.
For instance, if you are deleting a file, and the file does not exist, the code may throw the exception, but the caller has the option to ignore this if it was not concerned that the file did not exist, since it was trying to delete it anyhow. However, another caller, could error out with the absence of a file that was suppose to exist when it was being deleted.
In my opinion, the coding standard which you describe in your question is perfectly reasonable. And I think for the purposes of your project it would be better to tweak the "standard multiple classes per file" sniff so that it works with your code in this particular (special) case rather than waste your time tweaking your codebase to comply with "the letter of the law" for this particular sniff.
I agree with the assertion that it is better in general to avoid putting multiple class definitions in a single file. But every argument I've read (so far) for moving each and every Exception-derived class into its own separate file strikes me as an exhortation to "improve" code by making it less readable. As a human, I gain no maintainability benefit from cluttering my code with files containing a single line, each.
It's true that it is easier to write an autoloader, for example, if each class lives in its own file. And if you're generating/compiling your PHP code from some sort of meta-language then it costs you nothing to add extra levels to your directory structure. But I reject the conclusion that this way of organizing the code actually improves it in any useful-to-humans way.
EDIT:
For the record, I can see that it would be a good idea to move the definition of an Exception-derived class into its own file if it actually contains some "testable" logic. In such cases you might need to mock/stub the class when writing automated tests for the logic which uses the class, which would require you to be able to load the class definition separately from the logic which uses it. But this not the situation described in the original question, where the Exception-derived classes are all "empty".
I have two PHP apps which have twho class with the same name.
- app1 with a class "Project"
- app2 with a class "Project"
I have to use classes of the first app in the second one, but two class with one name cause an error ("PHP Fatal error: Cannot redeclare class Project ...").
I can't change class names.
I have to use PHP 5.2 (no namespace in PHP 5.2).
Is there a solution ?
May be :
use the class Project
undef this class (kind of "unset Project", is it possible with PHP ?)
include() the 2nd class
use the 2nd class
I don't know if it's possible with PHP (don't find any ressource about this) and I don't know a better way to manage this ...
I had this problem recently, with (embarrassingly) Joomla. I needed to find the versions of two different installations with one script, by loading up their two "version.php" files and then reading the class properties. But, of course, they're both called "JVersion", and it's impossible to require() both version.php files because of it.
After much thought, I realized eval() could take the place of require(). So I just read in the contents of the version.php files and change the names of the classes, then eval() that text, and then I can access both classes with different names. I bet you'd like some code. Here's what I ended up with...
$v15_txt=file_get_contents($old_dir.'/libraries/joomla/version.php');
$v15_txt=preg_replace('/class JVersion/i', 'class JVersion15', $v15_txt);
eval('?>'.$v15_txt);
$jvold=new JVersion15;
$old_version = $jvold->RELEASE.'.'.$jvold->DEV_LEVEL;
$v25_txt=file_get_contents($new_dir.'/libraries/cms/version/version.php');
$v25_txt=preg_replace('/class JVersion/i', 'class JVersion25', $v25_txt);
eval('?>'.$v25_txt);
$jvnew=new JVersion25;
$new_version = $jvnew->RELEASE.'.'.$jvnew->DEV_LEVEL;
Just modify it so it loads the right two files for your needs and renames them as required. Sorry you had to wait over a year for it. :-)
It's hard to believe PHP doesn't have some kind of "undeclare($classname)" function built-in. I couldn't even solve this with namespacing, because that requires changing the original two files. Sometimes ya just gotta think outside the framework.
Stop.
Whatever you are doing is wrong. Backup. Re-evaluate what you are doing and why.
If after that, you still need to do this. Pick an app, and do a find and replace on that class name in the app. If it was well designed, it should be unique and easy to do.
Document the hell out of the fact that you did this in whatever external documentation you are using.
PHP's __autoload() (documentation) is pretty interesting to me. Here's how it works:
You try to use a class, like new Toast_Mitten()(footnote1)
The class hasn't been loaded into memory. PHP pulls back its fist to sock you with an error.
It pauses. "Wait," it says. "There's an __autoload() function defined." It runs it.
In that function, you have somehow mapped the string Toast_Mitten to classes/toast_mitten.php and told it to require that file. It does.
Now the class is in memory and your program keeps running.
Memory benefit: you only load the classes you need. Terseness benefit: you can stop including so many files everywhere and just include your autoloader.
Things get particularly interesting if
1) Your __autoload() has an automatic way of determining the file path and name from the class name. For instance, maybe all your classes are in classes/ and Toast_Mitten will be in classes/toast_mitten.php. Or maybe you name classes like Animal_Mammal_Weasel, which will be in classes/animal/mammal/animal_mammal_weasel.php.
2) You use a factory method to get instances of your class.
$Mitten = Mitten::factory('toast');
The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"
Therefore, you can start out using a generic mitten throughout your code, and when the day comes that you need special behavior for toast, you just create that class and bam! - your code is using it.
My question is twofold:
(Fact) Do other languages have similar constructs? I see that Ruby has an autoload, but it seems that you have to specify in a given script which classes you expect to use it on.
(Opinion) Is this too magical? If your favorite language doesn't do this, do you think, "hey nifty, we should have that" or "man I'm glad Language X isn't that sloppy?"
1 My apologies to non-native English speakers. This is a small joke. There is no such thing as a "toast mitten," as far as I know. If there were, it would be a mitten for picking up hot toast. Perhaps you have toast mittens in your own country?
Both Ruby and PHP get it from AUTOLOAD in Perl.
http://perldoc.perl.org/perltoot.html#AUTOLOAD:-Proxy-Methods
http://perldoc.perl.org/AutoLoader.html
Note that the AutoLoader module is a set of helpers for common tasks using the AUTOLOAD functionality.
Do not use __autoload(). It's a global thing so, by definition, it's somewhat evil. Instead, use spl_autoload_register() to register yet another autoloader to your system. This allows you to use several autoloaders, what is pretty common practice.
Respect existing conventions. Every part of namespaced class name is a directory, so new MyProject\IO\FileReader(); should be in MyProject/IO/FileReader.php file.
Magic is evil!
The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"
Rather such tricky code, use simple and verbose one:
try {
$mitten = new ToastMitten();
// or $mitten = Mitten::factory('toast');
} catch (ClassNotFoundException $cnfe) {
$mitten = new BaseMitten();
}
I think this feature comes in very handy, and I have not seen any features like it else where. Nor have I needed these features else where.
Java has something similar. It's called a ClassLoader. Probably other languages too, but they stick with some default implementation.
And, while we're at this. It would have been nice if __autoload loaded any type of symbols, not just classes: constants, functions and classes.
See Ruby's Module#const_missing
I just learned this: Ruby has a method on Module called const_missing that gets called if you call Foo::Bar and Bar isn't in memory yet (although I suppose that Foo has to be in memory).
This example in ruby-doc.org shows a way to use that to implement an autoloader for that module. This is in fact what Rails uses to load new ActiveRecord model classes, according to "Eloquent Ruby" by Russ Olsen (Chapter 21, "Use method_missing for flexible error handling", which also covers const_missing).
It's able to do this because of the "convention over configuration" mindset: if you reference a model called ToastMitten, if it exists, it will be in app/models/toast_mitten.rb. If you could put that model any place you wanted, Rails wouldn't know where to look for it. Even if you're not using Rails, this example, and point #1 in my question, shows how useful it can be to follow conventions, even if you create them yourself.
In my project, say I am instantiating a class named SubClass, which extends an abstract class named AbstractClass. At the top of my files I include a file named bootstrap.inc, which includes AbstractClass in every file. Then, when I need it, I include SubClass which does not contain an include to AbstractClass.
If I include AbstractClass in the files of classes that extend it (such as SubClass), sometimes I am using multiple sub-classes in one file and will get an error. I would rather not include AbstractClass in every file via the bootstrap, since I am not always using it, but cannot think of a way to avoid this.
I have been advised that using include_once() is a sign of poor design, so have avoided that, although it would be one solution.
Is there an alternative method to include_once()?
First off - it's generally a good idea to stick to one class per file. If you're worried about performance, you're being paranoid. In production, you can always turn on APC with stat off.
Secondly - there's nothing wrong with include_once/require_once.
Unless you're going to set up some fancy autoloading magic, just stick to one class per file.
Absent some specific concern (that is, something articulable that you actually understand, not just some rumor you heard), the following pattern is perfectly fine:
<?PHP
require_once 'MyAbstract.class.php';
class Concrete extends MyAbstract {
//...
}
// end-of-file
PHP's Autoloading mechanism could be ideal for you.
That said, there's nothing wrong with include_once(). What that person talking about a design flaw was probably referring to is that a code flow that includes the same file more than once (thus making include_once() necessary over include() is most likely badly designed.