Question Quand utiliser soi-même plus de $ this?


En PHP 5, quelle est la différence entre l'utilisation self et $this?

Quand est-ce que chacun est approprié?


1775
2017-09-30 06:23


origine


Réponses:


Réponse courte

Utilisation $this pour se référer à l'actuel   objet. Utilisation self se référer à   classe actuelle. En d'autres termes, utilisez    $this->member pour les membres non statiques,   utilisation self::$member pour les membres statiques.

Réponse complète

Voici un exemple de correct l'utilisation de $this et self pour les variables de membre non statiques et statiques:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?>

Voici un exemple de Incorrect l'utilisation de $this et self pour les variables de membre non statiques et statiques:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo self::$non_static_member . ' '
           . $this->static_member;
    }
}

new X();
?>

Voici un exemple de polymorphisme avec $this pour les fonctions membres:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        $this->foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

Voici un exemple de suppression du comportement polymorphe en utilisant self pour les fonctions membres:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        self::foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

L'idée est que $this->foo() appelle le foo() La fonction membre de quel que soit> est le type exact de l'objet courant. Si l'objet est de type X, donc> appels X::foo(). Si l'objet est de type Y, il appelle Y::foo(). Mais avec> self :: foo (), X::foo() est toujours appelé.

De http://www.phpbuilder.com/board/showthread.php?t=10354489:

Par http://board.phpbuilder.com/member.php?145249-laserlight


1508
2017-09-30 06:29



Le mot-clé self fait NE PAS référez-vous simplement à la «classe actuelle», du moins pas d'une manière qui vous limite aux membres statiques. Dans le contexte d'un membre non statique, self fournit également un moyen de contourner le vtable (voir wiki sur vtable) pour l'objet actuel. Tout comme vous pouvez utiliser parent::methodName() appeler la version des parents d'une fonction, de sorte que vous pouvez appeler self::methodName() appeler l'implémentation des classes actuelles d'une méthode.

class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();

Cela va produire:

Bonjour, je suis Ludwig le geek
     Au revoir de Ludwig la personne

sayHello() utilise le $this pointeur, de sorte que le vtable est appelé pour appeler Geek::getTitle(). sayGoodbye() les usages self::getTitle(), donc le vtable n'est pas utilisé, et Person::getTitle() est appelé. Dans les deux cas, nous traitons la méthode d'un objet instancié, et avons accès à la $this pointeur dans les fonctions appelées.


710
2017-07-27 18:00



NE PAS UTILISER self::, utilisation static::

Il y a un autre aspect de soi: cela vaut la peine d'être mentionné. Agaçant self:: se réfère à la portée au moment de la définition et non au point d'exécution. Considérez cette classe simple avec deux méthodes:

class Person
{

    public static function status()
    {
        self::getStatus();
    }

    protected static function getStatus()
    {
        echo "Person is alive";
    }

}

Si nous appelons Person::status() nous verrons "La personne est en vie". Considérons maintenant ce qui se passe quand nous faisons une classe qui en hérite:

class Deceased extends Person
{

    protected static function getStatus()
    {
        echo "Person is deceased";
    }

}

Appel Deceased::status() nous nous attendrions à voir "La personne est décédée" mais ce que nous voyons est "La personne est en vie" car la portée contient la définition de la méthode d'origine lors de l'appel à self::getStatus() a été défini.

PHP 5.3 a une solution. la static:: L'opérateur de résolution implémente la "liaison statique tardive", ce qui est une manière élégante de dire qu'elle est liée à la portée de la classe appelée. Changer la ligne dans status() à static::getStatus() et les résultats sont ce que vous attendez. Dans les anciennes versions de PHP, vous devrez trouver un kludge pour le faire.

Voir Documentation PHP

Donc, pour répondre à la question pas comme demandé ...

$this-> fait référence à l'objet courant (une instance d'une classe), alors que static::se réfère à une classe


428
2017-07-24 15:08



Pour vraiment comprendre de quoi on parle quand on parle de self contre $this, nous devons creuser ce qui se passe au niveau conceptuel et pratique. Je ne pense pas vraiment que les réponses le fassent correctement, alors voici ma tentative.

Commençons par parler de ce que classe Et un objet est.

Classes et objets, conceptuellement

Et alors est une classe? Beaucoup de gens le définissent comme plan ou un modèle pour un objet. En fait, vous pouvez en lire plus A propos des cours en PHP ici. Et dans une certaine mesure c'est ce que c'est vraiment. Regardons un cours:

class Person {
    public $name = 'my name';
    public function sayHello() {
        echo "Hello";
    }
}

Comme vous pouvez le voir, il y a une propriété sur cette classe appelée $name et une méthode (fonction) appelée sayHello().

Ses très important de noter que le classe est une structure statique. Ce qui signifie que la classe Person, une fois défini, est toujours le même partout où vous le regardez.

Un objet d'autre part est ce qu'on appelle un exemple d'une classe. Cela signifie que nous prenons le "blueprint" de la classe, et l'utilisons pour faire une copie dynamique. Cette copie est maintenant spécifiquement liée à la variable dans laquelle elle est stockée. Par conséquent, toute modification d'un exemple est local à cette instance.

$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"

Nous créons de nouveaux instances d'une classe en utilisant le new opérateur.

Par conséquent, nous disons qu'une classe est une structure globale et un objet est une structure locale. Ne t'inquiète pas pour ça drôle -> syntaxe, nous allons entrer dans cela dans un petit peu.

Une autre chose dont nous devrions parler, c'est que nous pouvons vérifier si une instance est un instanceof une classe particulière: $bob instanceof Person qui renvoie un booléen si le $bob instance a été faite en utilisant le Person classe, ou un enfant de Person.

État définissant

Alors creusons un peu dans ce que contient réellement une classe. Il y a 5 types de "choses" qu'une classe contient:

  1. Propriétés - Pensez-y comme des variables que chaque instance contiendra.

    class Foo {
        public $bar = 1;
    }
    
  2. Propriétés statiques - Pensez à ceux-ci comme des variables qui sont partagées au niveau de la classe. Ce qui signifie qu'ils ne sont jamais copiés par chaque instance.

    class Foo {
        public static $bar = 1;
    }
    
  3. Méthodes - Ce sont des fonctions que chaque instance contiendra (et fonctionnera sur des instances).

    class Foo {
        public function bar() {}
    }
    
  4. Méthodes statiques - Ce sont des fonctions qui sont partagées dans toute la classe. Ils font ne pas opérer sur les instances, mais à la place sur les propriétés statiques seulement.

    class Foo {
        public static function bar() {}
    }
    
  5. Constantes - Constantes résolues par classe. Ne pas aller plus loin ici, mais en ajoutant pour l'exhaustivité:

    class Foo {
        const BAR = 1;
    }
    

Donc, fondamentalement, nous stockons des informations sur le conteneur de classe et d'objet en utilisant des "astuces" sur statique qui identifient si l'information est partagée (et donc statique) ou non (et donc dynamique).

Etat et Méthodes

À l'intérieur d'une méthode, l'instance d'un objet est représentée par $thisvariable. L'état actuel de cet objet est là, et la mutation (modification) d'une propriété entraînera une modification de cette instance (mais pas d'autres).

Si une méthode est appelée statiquement, le $this variable n'est pas défini. C'est parce qu'il n'y a pas d'instance associée à un appel statique.

La chose intéressante ici est comment les appels statiques sont faits. Alors parlons de la façon dont nous accédons à l'état:

Accès à l'état

Alors maintenant que nous avons stocké cet état, nous devons y accéder. Cela peut être un peu difficile (ou façon plus d'un bit), divisons donc ceci en deux points de vue: de l'extérieur d'une instance / classe (disons d'un appel de fonction normale, ou de l'étendue globale), et d'une instance / classe (depuis une méthode sur le objet).

De l'extérieur d'une instance / classe

De l'extérieur d'une instance / classe, nos règles sont assez simples et prévisibles. Nous avons deux opérateurs, et chacun nous dit immédiatement s'il s'agit d'une instance ou d'une classe statique:

  • -> - objet-opérateur - Ceci est toujours utilisé lorsque nous accédons à une instance.

    $bob = new Person;
    echo $bob->name;
    

    Il est important de noter que l'appel Person->foo n'a pas de sens (depuis Person est une classe, pas une instance). Par conséquent, c'est une erreur d'analyse.

  • :: - scope-resolution-operator - Ceci est toujours utilisé pour accéder à une propriété ou une méthode statique de classe.

    echo Foo::bar()
    

    En outre, nous pouvons appeler une méthode statique sur un objet de la même manière:

    echo $foo::bar()
    

    Ses extrêmement important de noter que lorsque nous faisons cela de dehors, l'instance de l'objet est cachée du bar() méthode. Ce qui signifie que c'est exactement la même chose que courir:

    $class = get_class($foo);
    $class::bar();
    

Donc, $this n'est pas défini dans l'appel statique.

De l'intérieur d'une instance / classe

Les choses changent un peu ici. Les mêmes opérateurs sont utilisés, mais leur signification devient nettement floue.

le objet-opérateur  -> est toujours utilisé pour effectuer des appels à l'état d'instance de l'objet.

class Foo {
    public $a = 1;
    public function bar() {
        return $this->a;
    }
}

Appeler le bar() méthode sur $foo (une instance de Foo) en utilisant l'opérateur-objet: $foo->bar() entraînera la version de l'instance de $a.

Voilà comment nous nous attendons.

La signification de la :: opérateur si les changements. Cela dépend du contexte de l'appel à la fonction en cours:

  • Dans un contexte statique

    Dans un contexte statique, les appels effectués en utilisant :: sera également statique. Regardons un exemple:

    class Foo {
        public function bar() {
            return Foo::baz();
        }
        public function baz() {
            return isset($this);
        }
    }
    

    Appel Foo::bar() appellera le baz() méthode statique, et donc $this volonté ne pas être peuplé. Il est à noter que dans les versions récentes de PHP (5.3+), cela déclenchera E_STRICT erreur, car nous appelons les méthodes non statiques de manière statique.

  • Dans un contexte d'instance

    Dans un contexte d'instance, d'autre part, les appels effectués en utilisant :: dépend du destinataire de l'appel (la méthode que nous appelons). Si la méthode est définie comme static, alors il utilisera un appel statique. Si ce n'est pas le cas, il transmettra les informations d'instance.

    Donc, en regardant le code ci-dessus, en appelant $foo->bar() reviendra true, puisque l'appel "statique" se passe à l'intérieur d'un contexte d'instance.

Avoir du sens? Je ne le pensais pas. C'est confu.

Mots-clés abrégés

Parce que lier tout ensemble en utilisant des noms de classe est plutôt sale, PHP fournit 3 mots-clés de "raccourci" de base pour faciliter la résolution de la portée.

  • self - Cela fait référence au nom de classe actuel. Alors self::baz() est le même que Foo::baz() dans le Foo class (n'importe quelle méthode dessus).

  • parent - Cela fait référence au parent de la classe actuelle.

  • static - Cela fait référence à la classe appelée. Grâce à l'héritage, les classes enfants peuvent remplacer les méthodes et les propriétés statiques. Donc les appelant en utilisant static au lieu d'un nom de classe nous permet de résoudre d'où vient l'appel, plutôt que le niveau actuel.

Exemples

La meilleure façon de comprendre cela est de commencer à regarder quelques exemples. Choisissons un cours:

class Person {
    public static $number = 0;
    public $id = 0;
    public function __construct() {
        self::$number++;
        $this->id = self::$number;
    }
    public $name = "";
    public function getName() {
        return $this->name;
    }
    public function getId() {
        return $this->id;
    }
}

class Child extends Person {
    public $age = 0;
    public function __construct($age) {
        $this->age = $age;
        parent::__construct();
    }
    public function getName() {
        return 'child: ' . parent::getName();
    }
}

Maintenant, nous regardons aussi l'héritage ici. Ignorez un instant que c'est un mauvais modèle d'objet, mais regardons ce qui se passe quand nous jouons avec ceci:

$bob = new Person;
$bob->name = "Bob";
$adam = new Person;
$adam->name = "Adam";
$billy = new Child;
$billy->name = "Billy";
var_dump($bob->getId()); // 1
var_dump($adam->getId()); // 2
var_dump($billy->getId()); // 3

Ainsi, le compteur d'ID est partagé entre les deux instances et les enfants (parce que nous utilisons self pour y accéder. Si nous avons utilisé static, nous pourrions le remplacer dans une classe enfant).

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

Notez que nous exécutons le Person::getName()  exemple méthode à chaque fois. Mais nous utilisons le parent::getName() pour le faire dans l'un des cas (l'affaire de l'enfant). C'est ce qui rend cette approche puissante.

Mot de prudence # 1

Notez que le contexte appelant est ce qui détermine si une instance est utilisée. Donc:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

N'est pas toujours vrai.

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

C'est maintenant vraiment bizarre ici. Nous appelons une classe différente, mais le $this qui est passé à la Foo::isFoo() méthode est l'instance de $bar.

Cela peut causer toutes sortes de bugs et WTF-ery conceptuel. Donc, je suggère fortement d'éviter le :: opérateur à partir de méthodes d'instance sur tout sauf les trois mots clés virtuels "raccourcis" (static, self, et parent).

Mot de prudence # 2

Notez que les méthodes statiques et les propriétés sont partagées par tout le monde. Cela les rend essentiellement des variables globales. Avec tous les mêmes problèmes qui viennent avec les globals. Donc, je serais vraiment hésitant à stocker des informations dans des méthodes / propriétés statiques, sauf si vous êtes à l'aise avec le fait qu'il soit vraiment mondial.

Motif de prudence # 3

En général, vous voudrez utiliser ce que l'on appelle Late-Static-Binding en utilisant static au lieu de self. Mais notez qu'ils ne sont pas la même chose, en disant "toujours utiliser static au lieu de self est vraiment à courte vue. Au lieu de cela, arrêtez-vous et pensez à l'appel que vous voulez faire et pensez si vous voulez que les classes enfants puissent remplacer cette fonction. statique résolu appel.

TL / DR

Dommage, retournez-y et lisez-le. C'est peut-être trop long, mais c'est long car c'est un sujet complexe

TL / DR # 2

OK bien. En bref, self est utilisé pour référencer le nom de la classe actuelledans une classe, où $this se réfère à l'objet actuel exemple. Notez que self est un raccourci copier / coller. Vous pouvez le remplacer en toute sécurité par votre nom de classe, et tout ira bien. Mais $this est une variable dynamique qui ne peut pas être déterminée à l'avance (et peut même ne pas être votre classe).

TL / DR # 3

Si l'opérateur-objet est utilisé (->), alors vous toujours sais que vous avez affaire à une instance. Si l'opérateur scope-resolution-operator est utilisé (::), vous avez besoin de plus d'informations sur le contexte (sommes-nous déjà dans un contexte-objet, sommes-nous en dehors d'un objet, etc.).


228
2018-06-10 15:21



self (pas $ self) se réfère à la type de classe, où comme $this se réfère à l'actuel exemple de la classe. self est à utiliser dans les fonctions membres statiques pour vous permettre d'accéder aux variables membres statiques. $this est utilisé dans les fonctions membres non statiques et fait référence à l'instance de la classe sur laquelle la fonction membre a été appelée.

Car this est un objet, vous l'utilisez comme: $this->member

Car self n'est pas un objet, c'est essentiellement un type qui se réfère automatiquement à la classe actuelle, vous l'utilisez comme: self::member


109
2017-09-30 07:26



$this-> est utilisé pour désigner une instance spécifique des variables (variables membres) ou des méthodes d'une classe.

Example: 
$derek = new Person();

$ derek est maintenant une instance spécifique de Person. Chaque personne a un prénom et un nom de famille, mais $ derek a un prénom spécifique et un nom de famille (Derek Martin). Dans l'instance $ derek, nous pouvons nous référer à ceux-ci comme $ this-> first_name et $ this-> last_name

ClassName :: est utilisé pour désigner ce type de classe, et ses variables statiques, méthodes statiques. Si cela vous aide, vous pouvez remplacer mentalement le mot "statique" par "partagé". Parce qu'ils sont partagés, ils ne peuvent pas se référer à $ this, qui fait référence à une instance spécifique (non partagée). Les variables statiques (c'est-à-dire static $ db_connection) peuvent être partagées entre toutes les instances d'un type d'objet. Par exemple, tous les objets de base de données partagent une seule connexion (connexion $ statique).

Exemple de variables statiques: Imaginons que nous ayons une classe de base de données avec une seule variable membre: static $ num_connections; Maintenant, mettez ceci dans le constructeur:

function __construct()
{
    if(!isset $num_connections || $num_connections==null)
    {
        $num_connections=0;
    }
    else
    {
        $num_connections++;
    }
}

Tout comme les objets ont des constructeurs, ils ont aussi des destructeurs, qui sont exécutés quand l'objet meurt ou est détruit:

function __destruct()
{
    $num_connections--;
}

Chaque fois que nous créons une nouvelle instance, cela augmente notre compteur de connexion de un. Chaque fois que nous détruisons ou cessons d'utiliser une instance, le compteur de connexion diminue de un. De cette façon, nous pouvons surveiller le nombre d'instances de l'objet de base de données que nous utilisons avec:

echo DB::num_connections;

Parce que $ num_connections est statique (partagé), il reflétera le nombre total d'objets de base de données actifs. Vous avez peut-être vu cette technique utilisée pour partager des connexions de base de données entre toutes les instances d'une classe de base de données. Cela est dû au fait que la création de la connexion à la base de données prend beaucoup de temps. Il est donc préférable d'en créer une seule et de la partager (c'est ce que l'on appelle un motif Singleton).

Les méthodes statiques (c'est-à-dire Public static View :: format_phone_number ($ digits)) peuvent être utilisées SANS instanciation préalable de l'un de ces objets (c'est-à-dire qu'elles ne renvoient pas en interne à $ this).

Exemple de méthode statique:

public static function prettyName($first_name, $last_name)
{
    echo ucfirst($first_name).' '.ucfirst($last_name);
}

echo Person::prettyName($derek->first_name, $derek->last_name);

Comme vous pouvez le voir, la fonction statique publique prettyName ne sait rien de l'objet. C'est juste de travailler avec les paramètres que vous passez, comme une fonction normale qui ne fait pas partie d'un objet. Pourquoi se soucier, alors, si nous pouvions simplement l'avoir en tant que partie de l'objet?

  1. Premièrement, attacher des fonctions aux objets vous aide à organiser les choses pour que vous sachiez où les trouver.
  2. Deuxièmement, cela empêche les conflits de noms. Dans un grand projet, il est probable que deux développeurs créent des fonctions getName (). Si l'on crée un ClassName1 :: getName (), et l'autre crée ClassName2 :: getName (), cela ne pose aucun problème. Pas de conflit. Yay méthodes statiques!

SOI:: Si vous codez à l'extérieur l'objet auquel vous voulez référencer la méthode statique, vous devez l'appeler en utilisant le nom de l'objet View :: format_phone_number ($ phone_number); Si vous codez à l'intérieur l'objet qui a la méthode statique à laquelle vous voulez vous référer, vous pouvez non plus utilise le nom de l'objet View :: format_phone_number ($ pn), OU vous pouvez utiliser le raccourci self :: format_phone_number ($ pn)

La même chose vaut pour les variables statiques: Exemple: Voir :: templates_path versus self :: paths_path

Dans la classe DB, si nous faisions référence à une méthode statique d'un autre objet, nous utiliserions le nom de l'objet: Exemple: Session :: getUsersOnline ();

Mais si la classe DB voulait se référer à sa propre variable statique, elle dirait simplement: Exemple: auto :: connexion;

J'espère que cela aidera à éclaircir les choses :)


93
2017-10-22 17:52



De ce blog:

  • self se réfère à la classe actuelle
  • self peut être utilisé pour appeler des fonctions statiques et des variables de membre statiques de référence
  • self peut être utilisé à l'intérieur des fonctions statiques
  • self peut également désactiver le comportement polymorphe en contournant le vtable
  • $this se réfère à l'objet actuel
  • $this peut être utilisé pour appeler des fonctions statiques
  • $this ne devrait pas être utilisé pour appeler des variables membres statiques. Utilisation self au lieu.
  • $this ne peut pas être utilisé à l'intérieur de fonctions statiques

27
2018-05-10 12:00



En PHP, vous utilisez le mot-clé self pour accéder aux propriétés et méthodes statiques.

Le problème est que vous pouvez remplacer $this->method() avec self::method()partout, peu importe si method() est déclaré statique ou non. Alors lequel devriez-vous utiliser?

Considérez ce code:

class ParentClass {
    function test() {
        self::who();    // will output 'parent'
        $this->who();   // will output 'child'
    }

    function who() {
        echo 'parent';
    }
}

class ChildClass extends ParentClass {
    function who() {
        echo 'child';
    }
}

$obj = new ChildClass();
$obj->test();

Dans cet exemple, self::who() sortira toujours 'parent', tandis que $this->who() dépendra de la classe de l'objet.

Maintenant, nous pouvons voir que le soi se réfère à la classe dans laquelle il est appelé, tandis que $this se réfère à la classe de l'objet courant.

Donc, vous devriez utiliser soi-même seulement quand $this n'est pas disponible ou lorsque vous ne souhaitez pas autoriser les classes descendantes à remplacer la méthode en cours.


23
2017-12-29 13:20



Dans une définition de classe, $ this fait référence à l'objet courant, tandis que self fait référence à la classe actuelle.

Il est nécessaire de se référer à un élément de classe en utilisant self, et de se référer à un élément d'objet en utilisant $ this.

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  

19
2018-05-08 06:58



Voici un exemple d'utilisation correcte de $ this et self pour non-static   et les variables de membre statiques:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?> 

17
2017-12-06 11:26