Переопределение статических членов класса в PHP5

smokemaker

Guest
Переопределение статических членов класса в PHP5

Здравствуйте!
При реализации некоего проекта есть желание использовать статические члены классов (атрибуты классов) для того, чтобы не зная их характеристик их можно было опросить и все узнать. Делается это для того, чтобы безболезненно можно было добавлять к проекту некоторую новую функциональность. Не уверен, что это лучшее решение, однако вот какая незадача: при выполнении нижеприведенного кода
PHP:
<?php
class MyParent{
	static $test = 1;
}
class MyChild extends MyParent{
	static $test = 2;
}
?>
Выдается следующая ошибка:
Fatal error: cannot redeclare static public variable MyСhild::$test ...

По этому поводу 2 вопроса:
1. Описано ли где-то в явном виде, что такого делать нельзя (сам, к сожалению, не нашел)
2. Какие могут быть обходные пути решения проблемы?

Конфигурация: WinXP En Pro, Apache 1.3.29, PHP5 RC1 как модуль.

Спасибо.
 

tony2001

TeaM PHPClub
если это константы, то делать стоит так:
PHP:
class MyParent{ 
    const test = 1; 
} 
class MyChild extends MyParent{ 
	const test = 2; 
}
если это не константы, то почему чайлд меняет свойство, наследованное от родителя?
может, этот вариант нужен:
PHP:
class MyParent{ 
	function foo() {
	    static $test = 1; 
		return $test;
	}
} 
class MyChild extends MyParent{ 
	function foo() {
	    static $test = 2; 
		return $test;
	}
}

echo MyParent::foo();
echo MyChild::foo();
 

smokemaker

Guest
Да, я согласен, в данном случае, так как свойства постоянные, лучше использовать конструкции типа
PHP:
class MyParent{ 
    const test = 1; 
}
Но при такой реализации возникла другая сложность (которая, безусловно, обходится) - каким образом имея уже _экземпляр_ класса получить данное значение.
Очень хотелось получить одинаково простой способ доступа к свойствам класса как через сам класс, так и через экземпляр. Без использования каких-либо функций-обвязок.
 

tony2001

TeaM PHPClub
>каким образом имея уже _экземпляр_ класса получить данное значение.
так же, как и без экземпляра.
PHP:
echo MyChild::test;

//если очень хочется, то можно и так =)

class MyChild extends MyParent{ 
	const boo = 3;
	function foo() {
		return MyChild::boo;
	}
}
 

smokemaker

Guest
Неправильно сформулировал :)
Каким образом через экземпляр класса получить доступ к константам класса наиболее простым способом?
Желательно без обвязок, так как иначе их придется определять в каждом дочернем классе.
 

tony2001

TeaM PHPClub
>Каким образом через экземпляр класса получить доступ к константам класса
>наиболее простым способом?
>Желательно без обвязок, так как иначе их придется определять в каждом дочернем классе.
все равно не понимаю почему Class::const - это не то, что тебе надо.
константы - он ведь относятся к классу вообще, поэтому и доступ через класс, а не через объект.
приведи пример, плз.
возможно, станет более понятно.
 

tony2001

TeaM PHPClub
Ямерт
кстати, это не работает.

PHP:
class MyChild extends MyParent{ 
	const boo = 3;
}

$child = new MyChild;
echo $child->boo;
-~{}~ 14.04.04 12:46:

не работает потому, что это выводит 5, а не 3:
PHP:
class MyChild extends MyParent{ 
	const boo = 3;
	public $boo = 5;
}

$child = new MyChild;
echo $child->boo;
 

smokemaker

Guest
Вообще-то, я пробовал так обратиться к константам:
PHP:
$obj->const
Как-то не заработало. Сейчас не помню, как звучало сообщение об ошибке. Или это я тупил?
Однако же, насчет примера.
Итак, описания классов:
PHP:
class MyParent{ 
    const test = 1; 
} 
class MyChild extends MyParent{ 
    const test = 2; 
}
Потом в некоторый момент куда-то (не важно, куда) является объект. Точно известно, что это экземпляр класса MyParent или его дочернего класса. Но _заранее_ точно сказать нельзя, к какому конкретно классу принадлежит объект.
Вопрос в том, как через этот объект получить доступ к константам класса?
 

tony2001

TeaM PHPClub
>Точно известно, что это экземпляр класса MyParent или его дочернего класса.
>Но _заранее_ точно сказать нельзя, к какому конкретно классу принадлежит объект.
PHP:
if (is_a($object,'MyChild')) {
   echo MyChild::boo1;
}
elsif (is_a($object,'MyParent')) {
   echo MyParent::boo2;
}
else {
/* unknown */
}
либо называй константы одинаково, тогда еще проще:
PHP:
/* MyChild сюда тоже входит, т.к. наследуется от MyParent */
if (is_a($object,'MyParent')) {
   echo MyParent::boo;
}
else {
/* unknown */
}
 

smokemaker

Guest
Первый вариант невозможен, так как заранее неизвестно, какие классы вообще будут в системе.
А вот второй обязательно попробую. Просто мне казалось, что
при обращении
PHP:
MyParent::boo
мы попадаем в область видимости класса MyParent, и, таким образом, работаем только с его константами, а не с контантами дочерних классов.
 

tony2001

TeaM PHPClub
я имел ввиду, что is_a вернет true в с случае с MyChild.
но да, ты прав, я не учел, что там имя класса нужно указывать вполне определенное.
т.е. второй пример неправильный.

>Первый вариант невозможен, так как заранее неизвестно, какие классы вообще
>будут в системе.
тогда делай у этих классов единообразный интерфейс для обращения к подобным свойствам.
я пока не вижу другого выхода.
PHP:
interface Test {
	function foo();
}

class MyParent implements Test { 
	const test1 = 1;
	function foo() {
		return MyParent::test1;
	}
} 

class MyChild extends MyParent implements Test { 
	const test2 = 2;
	function foo() {
		return MyChild::test2;
	}
}

$child = new MyChild;
echo $child->foo();
 

smokemaker

Guest
Спасибо, сегодня вечером попробую.
Тогда еще пара вопросов:
1. Можно ли в интерфейсе объявлять свойства?
2. Наследуется ли реализация интерфейса дочерними классами?
 

smokemaker

Guest
Ага, спасибо, попробую, конечно.
Результаты опишу.

-~{}~ 15.04.04 10:16:

Вот, если интересно, результаты вчерашних изысканий.
Начнем с того, что константы класов в данном случае - действительно адекватный и правильный подход (спасибо, Тони).
Остается вопрос о том, как через экземпляр класса добраться до классовых констант. Тут хотелось бы как-нибудь использовать наследование, чтобы не писать обертки (или реализацию интерфейса) в каждом дочернем классе. То есть, механизм доступа хотелось бы описать один раз.
А тогда выходит, что, оказавшись в области видимости родительского класса, мы должны добраться до констант дочернего класса, к которому и принадлежит экземпляр $this. А это, как я понял, неизбежно влечет использование функции eval(), как это ни прискорбно.

В общем, получилось следующее:
PHP:
<?php
class MyParent{
	const test = 1;
	public $p = 0;
	function __get($name){
		if(!in_array($name, array_keys(get_object_vars($this)))){
			$str = "\$r = ".get_class($this)."::$name;";
			eval($str);
		}else{
			$r = $this->$name;
		}
		return $r;
	}
}
class MyChild extends MyParent{
	public $s = 3;
	const test = 27;
}
echo MyParent::test."<br>";
echo MyChild::test."<br>";
$t = new MyChild;
echo $t->p."<br>";
echo $t->s."<br>";
echo $t->test."<br>";
?>
В итоге,
1. механизм доступа описан один раз
2. к константам класса можно обращаться как к обычным свойствам
3. те константы класса, которые не изменяются относительно родительского класса, можно не переопределять
4. одним из ключевых моментов является использование eval(), что, само по себе, огорчает
 

tony2001

TeaM PHPClub
> $str = "\$r = ".get_class($this)."::$name;";
я поспрашиваю знающий народ про __CLASS__::const сегодня.
вообще, мне кажется немного странным, что синтаксис $obj = new $var; разрешен, а $var::func() или $var::const - нет.
скорее всего, конечно, что там есть какие-то подводные камни, о которых я не знаю.
 

smokemaker

Guest
Мне тоже это непонятно, пытался как-то найти решения, но собственные "тырканья" ни к чему не привели... Если узнаешь и напишешь - очень здорово будет :)
 

smokemaker

Guest
Тред прочитал, однако вопрос о $var::const остался открытым. Возможно, что-то упустил.
 
Сверху