web-dev-qa-db-fra.com

Appel de méthode non statique avec un double-colon (: :)

Pourquoi ne puis-je pas utiliser une méthode non statique avec la syntaxe des méthodes static (class :: method)? Est-ce une sorte de problème de configuration?

class Teste {

    public function fun1() {
        echo 'fun1';
    }
    public static function fun2() {
        echo "static fun2" ;
    }
}

Teste::fun1(); // why?
Teste::fun2(); //ok - is a static method
43
NakaBr

PHP est très souple avec les méthodes statiques et non statiques. Une chose que je ne vois pas remarquée ici est que si vous appelez une méthode non statique, ns de manière statique à partir d'une méthode non statique de la classe C, $this à l'intérieur de ns, fera référence à votre instance de C.

class A 
{
    public function test()
    {
        echo $this->name;
    }
}

class C 
{
     public function q()
     {
         $this->name = 'hello';
         A::test();
     }
}

$c = new C;
$c->q();// prints hello

Il s'agit en réalité d'une erreur si vous signalez des erreurs strictes, mais pas autrement.

30
davidtbernal

Ceci est une "bizarrerie" connue de PHP. C’est pour des raisons de conception que d’empêcher la rétro-propagation pour déterminer si nous avons instancié un objet il ya quelque temps ou non (rappelez-vous, PHP est interprété et non compilé). Cependant, l'accès à tout membre non statique, l'opérateur de résolution via scope si l'objet n'est pas instancié, générera une erreur fatale.

Avec l'aimable autorisation de PHP.net:

class User {
    const GIVEN = 1;  // class constants can't be labeled static nor assigned visibility
    public $a=2;
    public static $b=3;

    public function me(){
        echo "print me";
    }
     public static function you() {
        echo "print you";
    }
}

class myUser extends User {
}

// Are properties and methods instantiated to an object of a class, & are they accessible?
//$object1= new User();        // uncomment this line with each of the following lines individually
//echo $object1->GIVEN . "</br>";        // yields nothing
//echo $object1->GIVE . "</br>";        //  deliberately misnamed, still yields nothing
//echo $object1->User::GIVEN . "</br>";    // yields nothing
//echo $object1->a . "</br>";        // yields 2
//echo $object1->b . "</br>";        // yields nothing
//echo $object1->me() . "</br>";        // yields print me
//echo $object1->you() . "</br>";        // yields print you

// Are  properties and methods instantiated to an object of a child class,  & are accessible?
//$object2= new myUser();        // uncomment this line with each of the following lines individually
//echo $object2->GIVEN . "</br>";        // yields nothing
//echo $object2->a . "</br>";        // yields 2
//echo $object2->b . "</br>";        // yields nothing
//echo $object2->me() . "</br>";        // yields print me
//echo $object2->you() . "</br>";        // yields print you

// Are the properties and methods accessible directly in the class?
//echo User::GIVEN . "</br>";        // yields 1
//echo User::$a . "</br>";            // yields fatal error since it is not static
//echo User::$b . "</br>";            // yields 3
//echo User::me() . "</br>";        // yields print me
//echo User::you() . "</br>";        // yields print you

// Are the properties and methods copied to the child class and are they accessible?
//echo myUser::GIVEN . "</br>";        // yields 1
//echo myUser::$a . "</br>";        // yields fatal error since it is not static
//echo myUser::$b . "</br>";        // yields 3
//echo myUser::me() . "</br>";        // yields print me
//echo myUser::you() . "</br>";        // yields print you
?>
23
David Titarenco

Ceci est une PHP 4 compatibilité avec les versions antérieures. Dans PHP 4, vous ne pouvez pas différencier une méthode d'objet de la fonction globale écrite en tant que méthode de classe statique. Par conséquent, les deux ont fonctionné.

Cependant, avec les modifications apportées au modèle d'objet avec PHP 5 - http://php.net/oop5 -, le mot clé static a été introduit.

Et puis, depuis PHP 5.1.3, vous obtenez des avertissements standard stricts concernant ceux qui ressemblent à:

Normes strictes: La méthode non statique Foo :: bar () ne doit pas être appelée de manière statique

Et/ou:

Normes strictes: La méthode non statique Foo :: bar () ne doit pas être appelée de manière statique, en supposant que ceci est issu d'un contexte incompatible

que vous auriez dû activer pour votre configuration de développement. Il s’agit donc simplement d’une compatibilité ascendante à un moment où le langage ne pouvait pas être suffisamment différent, ce qui a donc été "défini" au moment de l’exécution.

De nos jours, vous pouvez le définir déjà dans le code, mais le code ne sera pas cassé si vous l'appelez toujours "faux". 

Quelques démos pour déclencher les messages d'erreur et montrer le comportement modifié sur différentes versions de PHP: http://3v4l.org/8WRQH

13
hakre

PHP 4 n'avait pas de mot clé statique (dans le contexte de la déclaration de fonction), mais permettait toujours d'appeler des méthodes de manière statique avec ::. Cela s'est poursuivi dans PHP 5 à des fins de compatibilité ascendante.

13
webbiedave

Vous pouvez le faire, mais votre code sera erroné si vous utilisez $this dans la fonction appelée fun1()

6
Jake N

WarningIn PHP 7, l'appel de méthodes non statiques est obsolète et génère un avertissement E_DEPRECATED. La prise en charge de l'appel statique de méthodes non statiques peut être supprimée à l'avenir.

Lien

4
Malus Jan

Dans la plupart des langues, vous aurez besoin d'une instance de la classe pour pouvoir utiliser des méthodes d'instance. Il semble que PHP crée une instance temporaire lorsque vous appelez une méthode d'instance avec l'opérateur de résolution d'étendue.

1
Jacob Relkin

Vous ne savez pas pourquoi PHP le permet, mais vous ne voulez pas prendre l’habitude de le faire. Votre exemple ne fonctionne que parce qu'il n'essaie pas d'accéder aux propriétés non statiques de la classe. 

Quelque chose d'aussi simple que:

<?php
class Foo {

    private $color;

    public function bar() {
        echo 'before';
        $this->color = "blue";
        echo 'after';
    }
}

Foo::bar();

entraînerait une erreur fatale

1
brian_d

J'ai remarqué que si vous appelez une méthode non statique self :: test () depuis une classe, aucun avertissement concernant une norme stricte ne sera émis, comme lorsque vous appelez Class :: test (). Je crois que cela n’est pas lié au LSB, puisque ma classe n’a pas été prolongée (testée sur php 5.5)?

0
bpile