views:

287

answers:

3

So, if you try to do a nested class like this:

//nestedtest.php

class nestedTest{
    function test(){
         class E extends Exception{}
         throw new E;
    }
}

You will get an error Fatal error: Class declarations may not be nested in [...]

but if you have a class in a separate file like so:

//nestedtest2.php

class nestedTest2{
    function test(){
         include('e.php');
         throw new E;
    }
}

//e.php
class E Extends Exception{}

So, why does the second hacky way of doing it work, but the non-hacky way of doing it does not work?

+1  A: 

The second way is not nesting of classes. You just have your both declarations in one file, which is different from your first example. In PHP you can have multiple class declarations in one file it is a organizational decision not a requirement.

Ivo Sabev
Still, he has a point: He is including the code within a function.
Pekka
@Pekka It's because of how include works: *When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.* See http://de3.php.net/manual/en/function.include.php
Gordon
Doesn't matter because they are in the same file. He can get the same effect with putting the Exception class in another file and including it or using __autoload.
Ivo Sabev
@Ivo Sabev: That is a good point, I never thought of `__autoload` like that yet I use it all the time...
SeanJA
+8  A: 

From the manual (http://php.net/manual/en/function.include.php):

When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.

Tom Haigh
+1 didn't know that
soulmerge
So, they have a global scope, and I can call all of the private and protected functions that the class has...
SeanJA
@SeanJA: because they have global scope, you will _not_ be able call those non-public methods of the class which contained the include()
Tom Haigh
Sorry, what I meant was I can call the private and protected methods in the include file, not within the class that was included because of the include.
SeanJA
+1  A: 

There's no good reason to define a class inside a method. The 2nd way "works" only in the sense that it doesn't throw an error - the class still exists in the same scope/namespace as all the other defined classes. So, you're not actually "nesting" a class in this scenario.

By the way, the reason it works is because a class is merely a definition - there is no execution involved with defining a class. So that file (e.php) is parsed as soon as you include it, and then its class becomes available to the current execution context. Only the executable portions of the code (i.e., throw new E;) will actually belong to the scope of the caller.

Peter Bailey
This actually came up because I was worried that the second way would not work because the first way does not... when it did, I was a bit perplexed.
SeanJA