-1

I have a file created with classpreloader and some custom code which compresses a bunch of class files into a single file for distribution:

https://raw.githubusercontent.com/jnvsor/kint/1efd147f9831ade2e03921f7111ced07428556ab/build/kint.php

According to travis this fails on everything except nightly, with an error:

Fatal error: unknown class Kint_Renderer_Text in /home/travis/build/jnvsor/kint/build/kint.php on line 315

As you can see on line 315 is a class Kint_Renderer_Plain extends Kint_Renderer_Text which is defined later in the file with class Kint_Renderer_Text extends Kint_Renderer on line 418.

One would assume that this means class order in a single file is significant.

But when I sort() the source files before building the release file, travis says that everything went perfectly smoothly, despite the fact that the new file also has similar cases:

https://raw.githubusercontent.com/jnvsor/kint/1a657f06cd693b3f9db8f9458f900ef7bb378b53/build/kint.php

For example, class Kint_Object_Closure extends Kint_Object_Instance on line 1249 and class Kint_Object_Instance extends Kint_Object on line 1352

So the question becomes: What exactly are the ordering requirements for classes in PHP?

J V
  • 11,402
  • 10
  • 52
  • 72
  • From what I see, your first PHP file has `class Kint_Renderer_Plain extends Kint_Renderer_Text` before `class Kint_Renderer_Text extends Kint_Renderer`, while your second has `class Kint_Object_Instance extends Kint_Object` before `class Kint_Object_Closure extends Kint_Object_Instance`. So it looks like the order actually does change in the second file. That being said, see http://stackoverflow.com/questions/8337286/class-not-found-when-extending-class-that-implements-interface-in-php?noredirect=1&lq=1 for a better explanation. Long story short, yes the order does matter. – WOUNDEDStevenJones Apr 19 '17 at 21:14
  • Possible duplicate of [class not found when extending class that implements interface in PHP](http://stackoverflow.com/questions/8337286/class-not-found-when-extending-class-that-implements-interface-in-php) – WOUNDEDStevenJones Apr 19 '17 at 21:18
  • No, the second has the `Kint_Object_Closure` definition before the `Kint_Object_Instance` definition. That's why it's strange. And there are no interfaces in there so it can't be a duplicate of that question.. – J V Apr 19 '17 at 21:19
  • _"which compresses a bunch of class files into a single file for distribution"_ Don't reinvent the wheel, use [phar](http://php.net/manual/en/book.phar.php). – Alex Howansky Apr 19 '17 at 21:19

2 Answers2

0

What exactly are the ordering requirements for classes in PHP

Class must exists to be extended. So if class A extends class B and B is unknown at the moment of instantiation of A your code will fail. You can use autoloader to solve that yet it will defeat the purpose of keeping all in one file (which is wrong idea anyway).

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
-1

And once again I end up answering my own question because no-one on SO can be bothered to read for more than 10 seconds...

Turns out PHP only checks for dependencies in the same file once, not recursively, and then fails to update the error message. As a result you get things like this:

<?php
class A extends B {} // boom: <b>Fatal error</b>:  Class 'B' not found...
class B extends C {}
class C {}

Which work fine when the dependencies dependency is reordered:

<?php
class A extends B {}
class C {}
class B extends C {}

This behaves the same way with more than 2 extends. If it's the 3rd class that can't find its extend it will still report the second couldn't be found:

<?php
class A extends B {} // boom: <b>Fatal error</b>:  Class 'B' not found...
class C extends D {}
class B extends C {}
class D {}

This is fixed in 7.2 (Still pre-release) where it will recursively check, or at least check deeper - since as I mentioned in the question this error doesn't occur in nightly.

J V
  • 11,402
  • 10
  • 52
  • 72