Статический метод может получить доступ к вызывающему объекту, ошибке или функции?

Я работал над своим приложением и обнаружил странное поведение методов, которые вызываются статически, но не определяются как статические, которые расширяют тот же класс. В конце концов, эти методы могут получать доступ и изменять защищенные переменные и методы вызывающей стороны. Вот пример моего кода:

<?php

class object
{
    private $version;

    protected $alteredBy = 'nobody';

    public function __construct()
    {
        $this->version    = PHP_VERSION;

        $this->objectName = get_class($this);

        echo sprintf("<pre><strong>New %s Created</strong>", $this->objectName);

    }

    public function __destruct()
    {
        echo sprintf("</pre><strong>Source Code</strong><div>%s</div>", highlight_file(__FILE__, true));
    }
}

class superApplication extends object
{
    public function __toString()
    {
        echo "\nCalling third party object statically like thirdParty::method()\n";

        echo thirdParty::method();

        echo "\nCalling third party object statically via call_user_func()\n";

        echo call_user_func(array('thirdParty','method'));

        echo sprintf("New Object params\n%s", print_r($this, true));

        return sprintf("%s: done\n", $this->objectName);
    }
}

class thirdParty extends object
{    
    public function method()
    {
        if(is_object($this))
        {
            $this->alteredBy = __CLASS__;

            return sprintf(
                "<span style=\"color:red\">Object '%s' was altered successfully by %s class</span>\n", 
                get_class($this),
                __CLASS__
            );
        }
        else return "Cannot access caller object\n\n";        
    }
}

print new superApplication;
?>

Это поведение не задокументировано, поэтому мне интересно, это ошибка или функция и может ли это привести к проблемам с безопасностью?

ОБНОВЛЕНИЕ. Я знаю, что $this не разрешен внутри статических методов, и такое поведение появилось в версии php 5.2.11.


person Nazariy    schedule 12.09.2010    source источник


Ответы (1)


Рассмотрим этот пример в PHP 5.3:

<?php
        error_reporting(E_ALL | E_STRICT);

        class A
        {
                private $a = 'A';
                protected $b= 'B';
                public $c = 'C';
        }

        class B extends A
        {
                public function __construct()
                {
                        var_dump($this->a, $this->b, $this->c);
                        C::test();
                        var_dump($this->a, $this->b, $this->c);
                }
        }

        class C extends A
        {
                public function test()
                {
                        $this->a = null;
                        $this->b = null;
                        $this->c = null;
                }
        }

        new B();
?>

Результат:

PHP Notice:  Undefined property: B::$a in ... on line 15
NULL
string(1) "B"
string(1) "C"
PHP Strict Standards:  Non-static method C::test() should not be called statically, assuming $this from incompatible context in ... on line 16
NULL
NULL
NULL

Что происходит, так это то, что указатель $this C::test() считается $this из экземпляра new B(). Таким образом, он действует как функция-член B, но с доступом C.

Он может получить доступ только к защищенным и общедоступным переменным из A и к общедоступным переменным из B.

Обратите внимание, что перед вызовом C::test() $this->a вызывало уведомление. После звонка больше не делал, потому что переменная создавалась внутри звонка. Но приватные переменные A никогда не были доступны.

Так что да, строго говоря, это считается недействительным в PHP 5.3. И даже если более ранние версии позволяют вам делать это без предупреждения (я не проверял и не исследовал это), вы никогда не должны полагаться на такое поведение, поскольку оно явно является злоупотреблением ООП.

person Matthew    schedule 16.09.2010