Does the Order of Class Definition Matter in PHP

Does the order of class definition matter in PHP?

Yes, it matters. This is mentioned as a note in object inheritance documentation:

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 classes that inherit other classes and interfaces.

I recommend to use autoloading to resolve class dependencies. That way classes are only loaded when they are actually needed and you don't have to bother with including every single PHP file by hand.

You have to keep every class in it's own file for this to work, though. But that's a good way to keep everything tidy and clean, anyway.

PHP class definition order

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.

In What order should you declare “id” and “class” for the same HTML element, and why?

There is no predefined order for the attributes in terms of passing w3c validation... it's completely up to you. Any order of HTML attributes will have no effect on performance either.

PHP order of parameters when declaring function

They are relatively arbitrary, however there's a two main methodologies I've seen. The least common is "Order of Use", this only makes sense in sequential functions, where $this comes before $that.

However the typical way is something along the lines of "most important" or required arguments. You don't want important, optional, optional, optional, optional, optional, important - because then you'll need the optional ones set to '' or null or false in order to define the last important one.

Something like function test( $data_key, $number_of_results = 5, $classes = '' ){} makes sense because you can call test( 'my_key' ); and get arguably usable results.

Where if it was function test( $number_of_results = 5, $classes = '', $data_key ){}, you would make the semi-optional arguments before data_key required in a sense that they have to be passed to the function first: test( 5, '', 'my_key' );

Does use statement order affect functionality in PHP?

When alias namespaces no.

When used in the class body for Traits may affect in certain scenarios related with the use of docblock annotations.

Best practice: ordering of public/protected/private within the class definition?

In Clean Code, Robert C. Martin advises coders to always put member variables at the top of the class (constants first, then private members) and methods should be ordered in such a way so that they read like a story that doesn't cause the reader to need to jump around the code too much. This is a more sensible way to organize code rather than by access modifier.

Does PHP required or included files need to follow the order?

You can think of the include family ( include_once, require, require_once ) as a cut and paste type operation. If you follow just envision php creating one big file, pasting the content from each include call ( in the top down order of execution ).

So you might have

index.php
includes.php
functions.php

And if you do this in index

include 'includes.php'
some_function();

And then in includes.php

include 'functions.php'

And then in functions php you have a function some_function(){} you can use this in the index file after the include, php will see it like this

include 'includes.php'
include 'functions.php'
some_function(){}
some_function();

In your example above you would not be able to call the class because you are calling it before including it. Like this

//include_once('includes/child1.php');
Test::test_function();

//include_once('includes/child2.php');
class Test
{
static function test_function() {

}
}

However that said I notice you defined a "method" around your call to Test::test_function() that method would need to be wrapped in a class to work, if that was the intended way then it depends when you instantiate that class, you must do that after the Test class is defined. So for that case we will assume that that method is in a class

 class Test2{
public static function initialize() {
Test::test_function()
}
}

Now if you use this class back inside of the parent file or anywhere after the include of child2.php then it will work, so in the parent file if you do this.

 include_once('includes/child1.php');
include_once('includes/child2.php');

Test2::initialize();

You would think of this as a big file like this

 class Test2{
public static function initialize() {
Test::test_function()
}
}

class Test
{
static function test_function() {

}
}

Test2::initialize();

It should be fine. You just cant call it before it is defined. Make sense?

All that said, I would strongly suggest looking into a PSR autoloader, that is the standard way of including classes these days.

Here is a good post on the topic

http://www.sitepoint.com/autoloading-and-the-psr-0-standard/

Update explination

I'll try to make this as simple as I can. The way PHP works is it loads a file and parses the code, this basically means it just checks the formatting for syntax errors or typos and any new functions or class definitions ( it only registers the names of that new stuff and checks the syntax ). Once that is done and passes it starts to execute the code from top to bottom.

Now when including a file it can't parse it right away because it needs to execute the includes, which it does not do during the initial parsing. After it runs the include it parses the new chunk of code, and then continues executing that new code from top to bottom until the end of the included file at which point it returns to the original file and continues on from the include deceleration.

So while it seems different that you can run a function before defining it in the same file, but not in an included file, it is actually the same behavior. This is because it needs to execute the file to know the functions or code that is in it. So if you call the function before the include, PHP hasn't had a chance to even look in the file yet. Some of this is because you could put an include in an if statement and then PHP would not need to include the file.

What it doesn't do is, parse the file run all the includes and then run the code. I hope that clarified how the process flow works.

queue classes has sense in php?

No, the order in which the two classes are defined in the source file doesn't matter. As long as both are defined in the same file you move them around at will.

If the classes are not defined in the same file then things can get a little more complicated, but not in a way that will impact this kind of code.

PHP: inherit from a class that implements an interface

Edit: On the off-chance that anyone else comes across this, I just stumbled across this answer that does a far better job of explaining things: Why can't you inherit from a not-yet-defined class which inherits from a not-yet-defined class?

The separate files aspect of this is actually irrelevant - you can reproduce the same behaviour by simply defining the classes/interfaces out of order.

I don't know nearly enough about PHP's internals to say why any of this happens, but if there is anything more than a very simple inheritance structure, then the classes need to be defined in order.

This works:

<?php
class b extends a {}
class a {}

This does not:

<?php
class c extends b {}
class b extends a {}
class a {}

You can cause similar weirdness when implementing interfaces, as in your question:

Works:

<?php
interface testInterface {}
class b extends a implements testInterface {}
class a {}

Doesn't work:

<?php
interface testInterface {}
class b extends a {}
class a implements testInterface {}

In short: Always declare your interfaces, classes and traits in the order in which they're used. PHP might be able to figure things out for you, but don't rely on it (and I suspect different versions will also behave in subtly different ways). The same conclusion was reached in this question, posted a few years ago by Taylor Otwell, of all people.



Related Topics



Leave a reply



Submit