8

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:

  1. A static method gets called in PublicCustomer.

  2. The autoloader finds and loads the correct file.

  3. 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).

  4. 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:

  1. Separate these classes out so that there is one file for each (this will produce a huge number of files)
  2. 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?

Community
  • 1
  • 1
user2353938
  • 143
  • 1
  • 4
  • 2
    You should go with method 1. How many classes do you have ? it should not be a lot of work. PHP autoloaders are based on filenames\Directories related to classnames\namespaces. There is no built-in package support in PHP. Anyway it should make your scripts more modular. Why the app would have to parse class1 and class2 when only class2 is required? – mpm May 06 '13 at 09:05
  • Is there anything that prevents you from modifying the ORM in a way that creates separate files for every class? This should easily resolve the issue and would be better anyway. ;) – Till Helge May 06 '13 at 09:06
  • I can separate the classes into separate files, but that would obviously multiply the number of files in the ORM. There are actually 5 classes per DB table, so this would increase the number of files five-fold. Some databases I manage have 300-400 tables, which would mean ~2000 files. Obviously it's not a great design, I'm just wondering how best to change it moving forward. – user2353938 May 06 '13 at 10:04
  • 2
    Cannot reproduce it myself. Can you prepare minimal code to reproduce it behaviour? – sectus May 08 '13 at 06:23
  • 2
    Cannot reproduce either, and cannot find other reports on what would be a severe breakage of functionality. As sectus said, are you able to reproduce on a simple example ? – Lepidosteus May 09 '13 at 23:53
  • So I've now recompiled PHP again and I can't reproduce the issue! It's the exact same code and set up, just recompiled. Bizarre. Thank you for replying. – user2353938 May 13 '13 at 19:46

2 Answers2

1

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.

y o
  • 1,143
  • 9
  • 14
0

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.
Community
  • 1
  • 1
Henrik
  • 2,771
  • 1
  • 23
  • 33