Как мне проверить в PHP, что я нахожусь в статическом контексте (или нет)?

Перед ES2017 и async/await (см. ниже для опции в ES2017), вы не можете использовать .forEach(), если хотите дождаться обещания, потому что обещания не блокируются. Javascript и обещания просто не работают.

  1. Вы можете связать несколько обещаний и сделать их инфраструктуру последовательности.
  2. Вы можете выполнять итерацию вручную и продвигать только итерацию когда предыдущее обещание заканчивается.
  3. Вы можете использовать библиотеку, подобную async или Bluebird, которая будет их упорядочивать для вас.

Существует множество различных альтернатив , но .forEach() не сделает этого для вас.


Вот пример последовательности, использующей цепочку обещаний с угловыми обещаниями (если objects - массив):

objects.reduce(function(p, val) {
    return p.then(function() {
        return doSomething(val);
    });
}, $q.when(true)).then(function(finalResult) {
    // done here
}, function(err) {
    // error here
});

И, используя стандартные обещания ES6, это будет:

objects.reduce(function(p, val) {
    return p.then(function() {
        return doSomething(val);
    });
}, Promise.resolve()).then(function(finalResult) {
    // done here
}, function(err) {
    // error here
});

Вот пример ручного секвенирования (если objects - массив), хотя это не сообщает завершение или ошибки, подобные описанному выше:

function run(objects) {
    var cntr = 0;

    function next() {
        if (cntr < objects.length) {
            doSomething(objects[cntr++]).then(next);
        }
    }
    next();
}

ES2017

В ES2017 функция async/wait позволяет вам «ждать» обещания выполнить перед продолжением итерации цикла при использовании не-функциональных циклов, таких как for или while:

[f 4]

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

29
задан Brian Tompsett - 汤莱恩 1 June 2015 в 22:22
поделиться

10 ответов

Попробуйте сделать следующее:

class Foo {
   function bar() {
      $static = !(isset($this) && get_class($this) == __CLASS__);
   }
}

Источник: seancoates.com через Google

56
ответ дан ash108 1 June 2015 в 22:22
поделиться

«Выкопать его из debug_backtrace ()» не так уж много работы. У debug_backtrace () есть член 'type', который является '::', если вызов статический, и '->', если это не так. Итак:

class MyClass {
    public function doStuff() {
        if (self::_isStatic()) {
            // Do it in static context
        } else {
            // Do it in object context
        }
    }

    // This method needs to be declared static because it may be called
    // in static context.
    private static function _isStatic() {
        $backtrace = debug_backtrace();

        // The 0th call is to _isStatic(), so we need to check the next
        // call down the stack.
        return $backtrace[1]['type'] == '::';
    }
}

11
ответ дан Chris Hoffman 1 June 2015 в 22:22
поделиться

Проверка того, установлено ли $this, не всегда будет работать.

Если вы вызываете статический метод изнутри объекта, тогда $this будет установлен как контекст вызывающего. Если вы действительно хотите получить информацию, я думаю, вам придется выкопать ее из debug_backtrace. Но зачем вам это вообще нужно? Скорее всего, вы могли бы изменить структуру своего кода таким образом, чтобы вы этого не сделали.

8
ответ дан troelskn 1 June 2015 в 22:22
поделиться

Тест для $this:

class Foo {

    function bar() {
        if (isset($this)) {
            echo "Y";
        } else {
            echo "N";
        }
    }
}

$f = new Foo();
$f->bar(); // prints "Y"

Foo::bar(); // prints "N"

Редактировать: Как указывает pygorex1, вы также можете принудительно метод, который будет оцениваться статически:

class Foo {

    static function bar() {
        if (isset($this)) {
            echo "Y";
        } else {
            echo "N";
        }
    }
}

$f = new Foo();
$f->bar(); // prints "N", not "Y"!

Foo::bar(); // prints "N"
3
ответ дан Boldewyn 1 June 2015 в 22:22
поделиться

Проверьте, определено ли $this

1
ответ дан K Prime 1 June 2015 в 22:22
поделиться

Я фактически использую эту строку кода во всех моих сценариях, она работает хорошо и предотвращает ошибки.

class B{
      private $a=1;
      private static $static=2;

      function semi_static_function(){//remember,don't declare it static
        if(isset($this) && $this instanceof B)
               return $this->a;
        else 
             return self::$static;
      }
}

Использование instanceof не является паранойей:

Если класс A вызывает класс B, статическая функция $this может существовать в области A; Я знаю, что это довольно запутано, но php делает это.

instanceof исправит это и позволит избежать конфликтов с классами, которые могут реализовывать ваши «полустатические» функции.

6
ответ дан Smamatti 1 June 2015 в 22:22
поделиться

Это старый вопрос, но я добавлю альтернативный ответ.

Существует два магических метода

__call($name, $arguments)
запускается при вызове недоступных методов в контексте объекта.

__callStatic($name, $arguments)
срабатывает при вызове недоступных методов в статическом контексте.

<?php
class MethodTest
{
    public function __call($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }

    /**  As of PHP 5.3.0  */
    public static function __callStatic($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context');  // As of PHP 5.3.0

Выходы

Вызов метода объекта 'runTest' в контексте объекта
Вызов статического метода 'runTest' в статическом контексте

1
ответ дан Brad Kent 1 June 2015 в 22:22
поделиться
<?

class A {
    function test() {
            echo isset($this)?'not static':'static';                                }

}

$a = new A();
$a->test();
A::test();
?>

Редактировать: избили его.

1
ответ дан Bill Zeller 1 June 2015 в 22:22
поделиться

Просто верните класс как новый внутри функции.

return new self();
-1
ответ дан Yelson Ramirez von Gronroos 1 June 2015 в 22:22
поделиться

Тестирование isset ($ this) не работало для меня, как упомянул troelskn «$ this будет установлен как контекст вызывающего абонента».

abstract class parent
{
    function bar()
    {
        if( isset( $this ) ) do_something();
        else static::static_bar();
    }

    function static static_bar()
    {
        do_something_in_static_context();
    }
}

class child extends parent
{
    ...
}

$foo = new child();
$foo->bar(); //results in do_something()
child::bar(); //also results in do_something()

В моем случае у меня есть родительский класс с объектом и статической контекстной функцией, которая выполняет ту же задачу в дочернем классе. isset ($ this) всегда возвращал true, однако я заметил, что хотя $ this переключается между классом child в объектном контексте и вызовом (?) класса в статическом контексте, чудесная магическая константа __class__ осталась родительской для класса!

Вскоре после нахождения функции is_a мы можем проверить, находимся ли мы в статическом контексте:

if(  is_a($this, __CLASS__) ) ...

Возвращает true в контексте объекта, false в статическом контексте.

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

К сожалению (для моего случая) я пока не могу найти способ вызвать static_bar(), так как $ this и static относятся к отдельному классу, а __class__ относится к родительскому классу. Мне нужен способ вызова child :: static_bar () ...

2
ответ дан Shiboe 1 June 2015 в 22:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: