static:: не аналог $this-> для статических классов?

ChAk

Новичок
Ранее я изходил из убеждения что static:: это аналог $this-> для статических классов.
Но сталкнулся не с неожиданным поведением, и понял что я не прав.
Пример:
PHP:
class A
{
	private $var = 1;

	public function foo()
	{
		echo($this->var);
	}
}

class B extends A
{
}

$b = new B();
$b->foo(); // работает как ожидалось, выводит 1
PHP:
class A
{
	private static $var = 1;

	public static function foo()
	{
		echo(static::$var); // здесь выдает ошибку "Fatal error: Cannot access property B::$var"
	}
}

class B extends A
{
}

B::foo();
Почему так происходит не понял. Буду благодарен если кто-нибудь поможет разобраться.

Чтение http://docs.php.net/manual/ru/language.oop5.static.php и http://docs.php.net/manual/ru/language.oop5.late-static-bindings.php не помогло
 

ChAk

Новичок
Я не о переводе просил. Просил объяснить почему разное поведение при обычном объеялвение работает, а при статическом нет, почему?
 

Absinthe

жожо
Я не о переводе просил.
Хреново. Потому что это сообщение содержит причину ошибки.

Просил объяснить почему разное поведение при обычном объеялвение работает, а при статическом нет, почему?
static::$var вызванное для B - это B::$var. А оно приватное.
 

ChAk

Новичок
Напишу для чего мне это нужно.
Прежде чем писать какой то класс я решаю нужно ли мне будет создавать несколько экземпляров или нет (это очень упрощено), если нет то пишу статический. Статически пишу точно так же как писал бы обычный только во все объявления добавляю static и вместо $this-> использую static:: . Ожидал что при таком подходе работать они должны одинаково, но как я написал выше так не происходить. Соответственно я что то понял не так на счет статических классов, а вот что именно не так я не понимаю. Прошу помощи, что бы объяснили, что именно не так в чем разница между обычным объявлением и статическим, что результат разный? И как надо?
Я не прошу читать лекцию на счет того чем отличается обычный класс от статического, прошу только кратко объяснить ключевой момент почему в моем примере аналогичный код ведет себя по разному, и если он не аналогичный, то почему.
 

AmdY

Пью пиво
Команда форума
потому что static:: это не тоже что self::
В твоём примере static указывает на класс B в котором нет такой переменной и код аналогичен
PHP:
class A
{
    private $var = 1;
}

class B extends A
{
	public function foo()
    {
        echo($this->var);
    }
}

$b = new B();
$b->foo();
 

Redjik

Джедай-мастер
AmdY
Ну self:: уж точно не аналог $this->
Да ну? 0_о

fixxxer
ТС запутал, все верно =)

ChAk
а зачем тебе позднее статическое связывание вообще?
исходя из твоего подхода - лепи все глобальными переменными, раз Registry не хочешь использовать, а плодишь статичные классы.
 

AmdY

Пью пиво
Команда форума
ChAk
конечно не аналог точно так же как статическое программирование не аналог ООП
self и static это аналоги имени класса.
 

ChAk

Новичок
Иван Redjik Матвеев
Врятли это какой то сильно обдуманный выбор. Просто в определенный момент я вынужден был расширять свой статисческий класс и сталкнулся с проблемой описанной выше.
 

Redjik

Джедай-мастер
ChAk
конечно не аналог точно так же как статическое программирование не аналог ООП
self и static это аналоги имени класса.
Хотя приходиться извращаться с AR yii - нужно было из кэша взять массив, если инстанциировать класс модели, то он автоматом соединение создает с бд, но если значение есть в кэше, значит оно не обновилось, значит и в базу лезть незачем, вот и приходится Pages::getUrlMap()
 

scorpion-ds

Новичок
Народ извиняюсь, что флейм развожу, но мне уже давно не понятно, что люди подразумевают под "статический класс"? Не так давно под пиво с друзьями спорили на этот счет, мне доказывали, что статический класс, это что-то особенное.

Я понимаю, что класс может содержать статические методы, свойства и что можно объявить конструктор как private, в самом конструкторе сделать "блокировку" на создание объекта через статические методы класса, но ведь по сути класс все равно остается обычным классом или может я какую-то главу по PHP пропустил?
 

Redjik

Джедай-мастер
scorpion-ds
так - что тебе конкретно непонятно?
не бывает статических классов - бывают статические свойства и методы
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Я не так хорош как Фанат в формулировках мыслей, но попробую объяснить, как смогу.
Тут есть проблема, что реализация наследования областей видимости в пхпешном ООП отличается от канонѣчного наследования в той же Яве, частично это вызвано тем, что в пхп возможно неявное объявление переменной, частично — автокастингом типов, частично — тяжелым прошлым с обратной совместимостью.
Сначала про нормальный ООП: $this внутри методов объекта это переменная, которая ссылается на этот самый экземпляр класса (объект), в котором к ней происходит обращение. Поэтому внутри метода объекта через $this доступны все объявленные или унаследованные свойства этого класса, независимо от их «наружной» области видимости.
Так вот private свойство отличается от protected тем, что оно не унаследуется в классе-потомке( но это не значит, что его нельзя переобъявить в этом потомке, поскольку в потомке его не существует)
PHP:
<?php
class A {
    private $var = 1;
    public function foo() {
        echo $this->var;
    }
}
class B extends A {
	public function nice() {
		echo $this->var;
	}
}
$b = new B();
$b->foo();  // работает нормально, т.к. метод принадлежит к классу А, выводит 1
$b->nice(); // переменная $var не унаследовалась в класс B, ошибка
PHP:
<?php
class A {
    private $var = 1;
    public function foo() {
        echo $this->var;
    }
}
class B extends A {
        private $var = 2;
	public function nice() {
		echo $this->var;
	}
}
$b = new B();
$b->foo();  // работает нормально, т.к. метод принадлежит к классу А, выводит 1!!!
$b->nice(); // работает нормально, т.к. переменная переобъявлена в классе B, выводит 2
Теперь про статические классы (точнее их не бывает, но для простоты можно назвать этим словом статические функции со статическими переменными, объявленными в одном классе). Тут важно понять что статические классы — это не ООП, потому что там нет объектов. Это практически, всего лишь сложные неймспейсы, такой хак, «псевдо-ООП», который тупо облегчает жизнь.
Однако у них тоже есть наследование, и в php 5.3 появилось еще позднее статическое связывание, и все это работает примерно так:
Оператор :: используется для разрешения (вычисления) области видимости то есть говоря по-простому, он определяет в каком «неймспейсе» (статическом классе) находится функция, переменная, или константа, и вычисляет (или вызывает) ее.
Поскольку класс это не экземпляр объекта, то область видимости объявленных переменных у класса всегда равна именно этому классу.
Например, поэтому parent::$value это не вызов «родителя» объекта, а лишь «узнавание» имя класса, который служит родителем для этого объекта (или статического класса) и обращение к нему, как некоторой переменной (функции) в «неймспейсе».
Внутри класса self:: тоже всего лишь содержит название «неймспейса» (статического класса), в котором он объявлен, это всего лишь «магическая» переменная, и не является аналогом ссылки на объект.
Появившийся static:: «эмулирует» наследование по правилам ООП, и добавляет возможность сослаться на тот «неймспейс», в котором произошло обращение. Но это все равно лишь вычисляемое имя класса, в следующем примере static:: == B:: (имя статического класса, в котором произошел вызов static:: ) и это обращение к чужому методу, обьявленному как private, а значит несуществующему в области видимости класса B. Это равносильно вызову B::$var.
PHP:
<?php
class A {
    private static $var = 1;
    public static function foo() {
        echo(static::$var); // здесь выдает ошибку "Fatal error: Cannot access property B::$var"
    }
}
class B extends A {}
B::foo();
Как-то сумбурно получилось, и если где-то я не прав, то надеюсь, гуру ООП меня поправят.
 

ChAk

Новичок
флоппик
Спасибо большое за столько подробное объяснение. На статические классы я теперь буду смотреть по-другому.
 

Redjik

Джедай-мастер
флоппик
стоп теперь я запутался уже, я вот сейчас открыл yii и смотрю как там рендериться layout, в контроллере у нас есть public свойство $layout, в родительском оно назначено одно, в потомке я назначаю другое...

тоесть

PHP:
class TestController extends Controller{
    
    public $layout = 'mylayout';

}

class Controller extends CController{

    public $layout='//layouts/column1';

}

class CController{

    public $layout;

public function render($view,$data=null,$return=false)
	{
		if($this->beforeRender($view))
		{
			$output=$this->renderPartial($view,$data,true);
			if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
				$output=$this->renderFile($layoutFile,array('content'=>$output),true);

			$this->afterRender($view,$output);

			$output=$this->processOutput($output);

			if($return)
				return $output;
			else
				echo $output;
		}
	}
}
Тоесть обращение от последнего ребенка к методу самого первого родителя идет.
Свойство при этом берется от ребенка.

PHP:
<?php
class A {
    private $var = 1;
    public function foo() {
        echo $this->var;
    }
}
class B extends A {
        private $var = 2;
    public function nice() {
        echo $this->var;
    }
}
$b = new B();
$b->foo();  // работает нормально, т.к. метод принадлежит к классу А, выводит 1!!!
$b->nice(); // работает нормально, т.к. переменная переобъявлена в классе B, выводит 2
Это точно так? Или это true только для private?

ЗЫ. и точно так же работал в каком то фрейме механизм с таблицами в бд.
там моделька сама создавала таблицы в бд, по умолчанию одно название, при наследовании оно переопределялось, точно помню свойство было не public, скорее всего protected
 

флоппик

promotor fidei
Команда форума
Партнер клуба
/me заведет блог. Когда-нибудь. :) Формулировка «интуитивного» понимания некоторых вещей в стройное описание значительно улучшает их реальное понимание.
 
Сверху