Как работают вложенные классы PHP?

Итак, если вы попытаетесь сделать вложенный класс следующим образом:

//nestedtest.php

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

Вы получите ошибку Fatal error: Class declarations may not be nested in [...]

но если у вас есть класс в отдельном файле, например:

//nestedtest2.php

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

//e.php
class E Extends Exception{}

Так почему же второй хакерский способ работает, а нехакерский не работает?


person SeanJA    schedule 09.04.2010    source источник


Ответы (3)


Из руководства (http://php.net/manual/en/function.include.php):

Когда файл включен, код, который он содержит, наследует переменную области действия строки, в которой происходит включение. Любые переменные, доступные в этой строке в вызывающем файле, будут доступны в вызываемом файле с этого момента.Однако все функции и классы, определенные во включенном файле, имеют глобальную область действия.

person Tom Haigh    schedule 09.04.2010
comment
Итак, они имеют глобальную область видимости, и я могу вызывать все частные и защищенные функции, которые есть у класса... - person SeanJA; 09.04.2010
comment
@SeanJA: поскольку они имеют глобальную область видимости, вы не сможете вызывать те непубличные методы класса, которые содержат include() - person Tom Haigh; 09.04.2010
comment
Извините, я имел в виду, что я могу вызывать частные и защищенные методы во включаемом файле, а не в классе, который был включен из-за включения. - person SeanJA; 09.04.2010

Второй способ — не вложенность классов. У вас просто есть обе декларации в одном файле, что отличается от вашего первого примера. В PHP вы можете иметь несколько объявлений классов в одном файле, это организационное решение, а не требование.

person Ivo Sabev    schedule 09.04.2010
comment
Тем не менее, он прав: он включает код в функцию. - person Pekka; 09.04.2010
comment
@Pekka Это связано с тем, как работает включение: Когда файл включен, содержащийся в нем код наследует область переменных строки, в которой происходит включение. Любые переменные, доступные в этой строке в вызывающем файле, будут доступны в вызываемом файле с этого момента. Однако все функции и классы, определенные во включаемом файле, имеют глобальную область действия. См. de3.php.net/manual/en/function.include.php - person Gordon; 09.04.2010
comment
Не имеет значения, потому что они находятся в одном файле. Он может получить тот же эффект, поместив класс Exception в другой файл и включив его или используя __autoload. - person Ivo Sabev; 09.04.2010
comment
Это хороший момент, я никогда не думал об этом __autoload, но я использую его все время... - person SeanJA; 09.04.2010

Нет веской причины определять класс внутри метода. Второй способ "работает" только в том смысле, что он не выдает ошибку - класс все еще существует в той же области/пространстве имен, что и все другие определенные классы. Таким образом, вы на самом деле не «вкладываете» класс в этот сценарий.

Кстати, причина, по которой это работает, заключается в том, что класс — это просто определение — определение класса не связано с выполнением. Таким образом, этот файл (e.php) анализируется, как только вы его включаете, а затем его класс становится доступным для текущего контекста выполнения. Только исполняемые части кода (т. е. throw new E;) будут фактически принадлежать области действия вызывающей стороны.

person Peter Bailey    schedule 09.04.2010
comment
На самом деле это появилось, потому что я беспокоился, что второй способ не сработает, потому что первый способ не работает... когда это сработало, я был немного озадачен. - person SeanJA; 09.04.2010