Firstly, this is a bit of a long one, so thank you for reading.
My issue is similar to this one:
Class not found in the same file
I have a custom-built framework originally written in 2008 for PHP 5 and it’s been upgraded over the years to work with PHP 5.3. I’ve been looking at 5.4 compatibility and have hit a serious issue.
The ORM layer automatically generates classes for each DB table. These classes all sit in one file per table and our autoloader loads that file when required.
For example, a ‘customer’ table in the ‘public’ schema (postgresql) would have the following classes:
PublicCustomer, PublicCustomerDBReader, PublicCustomerDBWriter.
Now this may not be the ideal set up, but it is what we currently have.
In PHP 5.3, if PublicCustomer was required, the file would be included, parsed and all of the above classes would become available. So if, for example, a static method is called on PublicCustomer, and that method calls something in PublicCustomerDBReader, that would work fine, since that class is in the same file.
In PHP 5.4, it looks like some optimisations have been done in the core. In the above scenario:
A static method gets called in PublicCustomer.
The autoloader finds and loads the correct file.
The PHP parser only parses up to where it needs; the PublicCustomer class. It has not parsed or instantiated the PublicCustomerDBReader class. I can confirm this by testing if the class exists and by seeing if the parser reaches the end of the file when it gets included, when the method is called (it doesn’t).
- The method in PublicCustomer then tries to call a method in PublicCustomerDBReader. This fails, since our autoloader has already required the file once.
It seems to me that I have two solutions:
- Separate these classes out so that there is one file for each (this will produce a huge number of files)
- Redesign the ORM layer so that multiple classes are not required.
Have I understood the issue above properly?
Does anyone know if an optimisation or change was made in PHP 5.4 that would cause this behaviour?
Are there any other potential solutions to the problem that I have not considered?
Place the reader/writer classes at the head of the file. Also you might consider filing a bug report, since the parser should only halt on errors.
Referring to the PHP Framework Interop Group and their autoloading standards PSR-0 and PSR-4 each class must have its own file with a name ending in
.php. Even if you have thousands of classes, this should’t be a problem for the file system.
With more than one class in a file you have to consider following aspects:
- For each class the autoloader must decide which file to load. If you have multiple classes in a file, each used class causes a load. Class files should be loaded once and not more, because classes cannot be redeclared. I do not recommend it, but you could handle this with your own autoloader, which remembers loaded files or tests for loaded classes.
- Classes placed within the same file and using each other is problematic. The problem is described in Derived class defined later in the same file “does not exist”? and answered by Jon.