Quand utiliser self over $ this?

1997

En PHP 5, quelle est la différence entre utiliser selfet $this?

Quand est-ce approprié?

Casey Watson
la source
doublon possible de New self vs new static
Orangepill
Je vais demander quelle est la différence entre: cont A; $ this-> A et self :: A
timmz

Réponses:

1728

Réponse courte

Utilisez $thispour faire référence à l'objet actuel. Utilisez selfpour faire référence à la classe actuelle. En d'autres termes, utilisez $this->memberpour les membres non statiques, utilisez self::$memberpour les membres statiques.

Réponse complète

Voici un exemple d' utilisation correcte de $thiset selfpour les variables membres 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 d' utilisation incorrecte de $thiset selfpour les variables membres 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 $thispour 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 à l'aide selfde 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 d' $this->foo()appeler la foo()fonction membre de quel que soit le type exact de l'objet actuel. Si l'objet est de type X, il appelle donc X::foo(). Si l'objet est de type Y, il appelle Y::foo(). Mais avec self :: foo (), X::foo()est toujours appelé.

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

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

John Millikin
la source
330
Cette réponse est trop simpliste. Comme indiqué dans d'autres réponses, selfest utilisé avec l'opérateur de résolution de portée ::pour faire référence à la classe actuelle; cela peut être fait à la fois dans des contextes statiques et non statiques. De plus, il est parfaitement légal d'utiliser $thispour appeler des méthodes statiques (mais pas pour référencer des champs).
Artefacto
50
Pensez également à utiliser static :: au lieu de :: self si vous êtes sur 5.3+. Cela peut vous causer des maux de tête incalculables sinon, consultez ma réponse ci-dessous pour savoir pourquoi.
Sqoo
25
-1. Cette réponse est trompeuse, lisez les autres réponses pour plus d'informations.
Pacerier
6
C'est peut-être trop simplifié, mais cela a répondu à ma question de niveau de base sans faire exploser ma tête. J'ai obtenu plus d'informations que j'ai trouvées plus bas, mais pour l'instant j'essayais juste de comprendre pourquoi j'ai frappé mes attributs de classe avec $ this-> attrib et les constantes de classe avec self :: constant. Cela m'a aidé à mieux comprendre
MydKnight
Et alors $this::?
James
742

Le mot-clé self ne fait PAS simplement référence à la «classe actuelle», du moins pas d'une manière qui vous limite aux membres statiques. Dans le contexte d'un membre non statique, selffournit également un moyen de contourner la vtable ( voir wiki sur vtable ) pour l'objet actuel. Tout comme vous pouvez utiliser parent::methodName()pour appeler la version parent d'une fonction, vous pouvez également appeler self::methodName()pour appeler l'implémentation de classes actuelle 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 produira:

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

sayHello()utilise le $thispointeur, donc la vtable est invoquée pour appeler Geek::getTitle(). sayGoodbye()utilise self::getTitle(), donc la vtable n'est pas utilisée et Person::getTitle()est appelée. Dans les deux cas, nous avons affaire à la méthode d'un objet instancié, et avons accès au $thispointeur dans les fonctions appelées.

nbeagle
la source
3
Cette réponse serait encore meilleure si vous commenciez par une règle générale plutôt que par une exception. C'est une question de style, pas d'expertise technique. C'est le meilleur exemple que j'ai jamais vu de la différence entre self :: et $ this->, mais c'est dommage de le cacher en réfutant d'abord une notion.
adjwilli
3
@adjwilli: Pourquoi ce mauvais style? Cela n'éveille-t-il pas la conscience si l'attente (thèse) du PO est d'abord désapprouvée (antithèse) puis l'explication est donnée comme synthèse?
hakre
1
Je trouve que la "classe actuelle" est vraiment problématique. Comme cette combinaison de mots peut être comprise à la fois comme "la classe où selfse trouve" / "la définition de classe, elle fait littéralement partie de" ainsi que "la classe de l'objet" (qui serait en fait static).
Jakumi
Et alors $this::?
James
1
@James - il n'y a aucune bonne raison d'utiliser $this::; tous les cas possibles sont déjà couverts par des syntaxes plus couramment utilisées. Selon ce que vous voulez dire, l' utilisation $this->, self::ou static::.
ToolmakerSteve
460

NE PAS UTILISER self::, utiliserstatic::

Il y a un autre aspect de self :: qui mérite d'être mentionné. Désagréablement self::fait référence à la portée au point de 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 vivante". Considérez maintenant ce qui se passe lorsque nous créons une classe qui hérite de ceci:

class Deceased extends Person
{

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

}

En appelant, Deceased::status()nous nous attendrions à voir «La personne est décédée», mais ce que nous voyons est «La personne est vivante», car la portée contient la définition de la méthode d'origine lorsque l'appel à a self::getStatus()été défini.

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

Voir la documentation PHP

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

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

Sqoo
la source
6
Et pour les constantes de classe?
Kevin Bond
53
"En appelant Deceased :: status (), nous nous attendrions à voir" La personne est décédée "". Non. Il s'agit d'un appel de fonction statique, il n'y a donc pas de polymorphisme impliqué.
cquezel
2
De tous les défauts de PHP, je ne pense pas que ce soit fou du tout. Sinon, comment permettraient-ils aux codeurs de désigner des méthodes sur la classe actuelle (au lieu de les rechercher dans la table virtuelle)? S'ils l'avaient nommé différemment (peut-être avec des traits de soulignement principaux), alors les gens qui veulent cette fonctionnalité la critiqueraient pour être laide. Sinon, quel que soit le nom sensé qu'ils pourraient utiliser, il semble qu'il y aurait toujours des gens facilement confus qui le critiqueraient pour être un comportement "insensé", probablement inconscient du fonctionnement même de la répartition des méthodes.
TNE
2
L'exemple me semble déroutant: je vois la getStatusméthode comme celle que j'appellerais pour une instance de classe, pas pour une classe.
Jānis Elmeris
1
@Sqoo - dire "NE PAS UTILISER self ::, use static ::" est un argument étrange à faire - ce n'est délibérément pas la même opération. Je pense que le point que vous faites valoir est "il est plus clair si vous utilisez le nom de classe réel" MyClass :: ", plutôt que" self :: " . Autrement dit, si vous voulez le comportement de self::, vous pouvez l'obtenir, moins prêter à confusion, en utilisant le nom de classe spécifique, par exemple MyClass::.
ToolmakerSteve
248

Pour vraiment comprendre de quoi nous parlons lorsque nous parlons de selfversus $this, nous devons réellement creuser ce qui se passe au niveau conceptuel et pratique. Je ne pense pas que l'une des réponses le fasse correctement, alors voici ma tentative.

Commençons par parler de ce qu'est une classe et un objet .

Classes et objets, conceptuellement

Alors, qu'est - ce qu'une classe ? Beaucoup de gens le définissent comme un plan directeur ou un modèle pour un objet. En fait, vous pouvez en savoir plus sur les classes en PHP ici . Et dans une certaine mesure, c'est ce que c'est vraiment. Regardons une classe:

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

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

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

Un objet d'autre part est ce qu'on appelle une instance d'une classe. Cela signifie que nous prenons le «plan directeur» de la classe et que nous l'utilisons pour faire une copie dynamique. Cette copie est désormais spécifiquement liée à la variable dans laquelle elle est stockée. Par conséquent, toute modification apportée à une instance est locale à cette instance.

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

Nous créons de nouvelles instances d'une classe en utilisant l' newopérateur.

Par conséquent, nous disons qu'une classe est une structure globale et un objet est une structure locale. Ne vous inquiétez pas de cette drôle de ->syntaxe, nous allons y revenir un peu.

Une autre chose dont nous devrions parler, c'est que nous pouvons vérifier si une instance est une instanceofclasse particulière: $bob instanceof Personqui retourne un booléen si l' $bobinstance a été créée en utilisant la Personclasse, ou un enfant de Person.

Définition de l'État

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

  1. Propriétés - Considérez-les comme des variables que chaque instance contiendra.

    class Foo {
        public $bar = 1;
    }
    
  2. Propriétés statiques - Considérez-les comme des variables partagées au niveau de la classe. Cela 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 les instances).

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

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

    class Foo {
        const BAR = 1;
    }
    

Donc, fondamentalement, nous stockons des informations sur la classe et le conteneur d'objets en utilisant des "astuces" sur l' électricité statique qui identifient si les informations sont partagées (et donc statiques) ou non (et donc dynamiques).

État et méthodes

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

Si une méthode est appelée statiquement, la $thisvariable n'est pas définie . En effet, aucune instance n'est associée à un appel statique.

La chose intéressante ici est de savoir comment les appels statiques sont effectués. Parlons donc de la façon dont nous accédons à l'État:

État d'accès

Alors maintenant que nous avons enregistré cet état, nous devons y accéder. Cela peut devenir un peu délicat (ou bien plus qu'un peu), alors divisons cela en deux points de vue: de l'extérieur d'une instance / classe (disons à partir d'un appel de fonction normal ou de la portée globale) et à l'intérieur d'une instance / classe (à partir d'une méthode sur l'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 si nous avons affaire à une instance ou à 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->foon'a pas de sens (puisqu'il Persons'agit d'une classe et non d'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()

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

    echo $foo::bar()

    Il est extrêmement important de noter que lorsque nous faisons cela de l'extérieur , l'instance de l'objet est masquée de la bar()méthode. Cela signifie que c'est exactement la même chose que la course:

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

Par conséquent, $thisn'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.

L' opérateur d'objet -> 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;
    }
}

L'appel de la bar()méthode sur $foo(une instance de Foo) à l'aide de l'opérateur objet: $foo->bar()entraînera la version de l'instance de $a.

Voilà donc ce que nous attendons.

La signification de l' ::opérateur change cependant. Cela dépend du contexte de l'appel à la fonction courante:

  • Dans un contexte statique

    Dans un contexte statique, tous les appels effectués à l'aide de ::seront également statiques. Regardons un exemple:

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

    L'appel Foo::bar()appellera la baz()méthode de manière statique et ne$this sera donc pas rempli. Il convient de noter que dans les versions récentes de PHP (5.3+), cela déclenchera une E_STRICTerreur, car nous appelons des méthodes non statiques de manière statique.

  • Dans un contexte d'instance

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

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

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

Mots-clés raccourcis

Parce que tout lier 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. C'est self::baz()la même chose que Foo::baz()dans la Fooclasse (n'importe quelle méthode).

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

  • static- Il s'agit de la classe appelée. Grâce à l'héritage, les classes enfants peuvent remplacer les méthodes et les propriétés statiques. Ainsi, les appeler à l'aide staticd'un nom de classe nous permet de déterminer d'où vient l'appel, plutôt que le niveau actuel.

Exemples

La façon la plus simple de comprendre cela est de commencer à regarder quelques exemples. Choisissons une classe:

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 examinons également l'héritage ici. Ignorez un instant qu'il s'agit d'un mauvais modèle d'objet, mais regardons ce qui se passe lorsque 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 l'utilisons selfpour y accéder. Si nous l'utilisions 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 la méthode d' Person::getName() instance à chaque fois. Mais nous utilisons le parent::getName()pour le faire dans l'un des cas (le cas des enfants). C'est ce qui rend cette approche puissante.

Mot de prudence # 1

Notez que le contexte d'appel 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)

Maintenant, c'est vraiment bizarre ici. Nous appelons une classe différente, mais celle $thisqui est transmise à la Foo::isFoo()méthode est l'instance de $bar.

Cela peut provoquer toutes sortes de bugs et WTF-ery conceptuel. Donc , je suggère fortement d' éviter l' ::opérateur à partir de méthodes d'instance sur quoi que ce soit , sauf ces trois mots - clés « raccourci » virtuels ( static, selfet parent).

Mot de prudence # 2

Notez que les méthodes et propriétés statiques sont partagées par tous. Cela en fait essentiellement des variables globales. Avec tous les mêmes problèmes que les globaux. Donc, j'hésiterais vraiment à stocker des informations dans des méthodes / propriétés statiques à moins que vous ne soyez à l'aise avec le fait qu'elles soient vraiment globales.

Mot de prudence # 3

En général, vous voudrez utiliser ce que l'on appelle la liaison statique tardive en utilisant staticau lieu de self. Mais notez que ce n'est pas la même chose, donc dire "toujours utiliser à la staticplace de selfest 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 soient capables de remplacer cette résolution statique appel.

TL / DR

Dommage, revenez en arrière et lisez-le. C'est peut-être trop long, mais c'est aussi long car c'est un sujet complexe

TL / DR # 2

OK bien. En bref, selfest utilisé pour référencer le nom de la classe actuelle dans une classe, où as $thisfait référence à l' instance d' objet actuelle . Notez qu'il selfs'agit d'un raccourci copier / coller. Vous pouvez le remplacer en toute sécurité par le nom de votre classe, et cela fonctionnera bien. Mais $thisc'est une variable dynamique qui ne peut pas être déterminée à l'avance (et peut-être même pas votre classe).

TL / DR # 3

Si l'opérateur objet est utilisé ( ->), alors vous savez toujours 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 d'objet? Sommes-nous en dehors d'un objet? Etc).

ircmaxell
la source
1
Word of Caution # 1: $ this ne sera pas défini lors de l'appel d'une méthode statique: 3v4l.org/9kr0e
Mark Achée
Eh bien ... $thisne sera pas défini si vous suivez les "normes strictes" et n'appelez pas de méthodes statiques qui ne sont pas définies comme statiques. Je vois le résultat que vous avez expliqué ici: 3v4l.org/WeHVM D'accord, vraiment bizarre.
Mark Achée
2
Après avoir lu la longue description complètement, je me sentais paresseux pour faire défiler à nouveau ci-dessus pour le voter. Je plaisante, je l'ai voté: D. Merci c'est très utile.
Mr_Green
3
serait bien d'ajouter une explication claire sur la différence entre self :: $ property et self :: property; Je pense que c'est assez déroutant aussi
Tommaso Barbugli
1
WoC # 1 se comporte différemment depuis PHP 7. Comme Foo::isFoo()on l'appelle statiquement, $thisne sera pas défini. C'est un comportement plus intuitif à mon avis. - Un autre résultat différent est donné s'il Bardevait s'étendre de Foo. Ensuite, l'appel Foo::isFoo()serait en fait dans le contexte de l'instance (non spécifique à PHP7).
Kontrollfreak
117

self(pas $ self) fait référence au type de classe, où as $thisfait référence à l' instance actuelle de la classe. selfest à utiliser dans les fonctions membres statiques pour vous permettre d'accéder aux variables membres statiques. $thisest utilisé dans les fonctions membres non statiques et est une référence à l'instance de la classe sur laquelle la fonction membre a été appelée.

Parce que thisc'est un objet, vous l'utilisez comme:$this->member

Parce que ce selfn'est pas un objet, c'est fondamentalement un type qui fait automatiquement référence à la classe actuelle, vous l'utilisez comme:self::member

MrZebra
la source
97

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

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 et un nom de famille spécifiques (Derek Martin). Dans l'instance $ derek, nous pouvons les désigner comme $ this-> first_name et $ this-> last_name

ClassName :: est utilisé pour faire référence à ce type de classe, et à ses variables statiques, aux méthodes statiques. Si cela peut vous aider, vous pouvez mentalement remplacer le mot "statique" par "partagé". Parce qu'ils sont partagés, ils ne peuvent pas faire référence à $ this, qui fait référence à une instance spécifique (non partagée). Les variables statiques (ie statique $ 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).

Variables statiques Exemple: Imaginez que nous avons 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 lorsque l'objet meurt ou n'est pas défini:

function __destruct()
{
    $num_connections--;
}

Chaque fois que nous créons une nouvelle instance, cela augmentera notre compteur de connexions d'une unité. Chaque fois que nous détruisons ou cessons d'utiliser une instance, cela diminue le compteur de connexions d'une unité. 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 qu'on appelle un modèle Singleton).

Les méthodes statiques (c'est-à-dire View :: format_phone_number ($ digits) statiques publiques) peuvent être utilisées SANS d'abord instancier l'un de ces objets (c'est-à-dire qu'elles ne se réfèrent 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. Cela fonctionne simplement avec les paramètres que vous transmettez, comme une fonction normale qui ne fait pas partie d'un objet. Pourquoi s'embêter, alors, si nous pouvions simplement ne pas l'avoir comme partie de l'objet?

  1. Tout d'abord, attacher des fonctions aux objets vous aide à garder les choses organisées, vous savez donc où les trouver.
  2. Deuxièmement, il empêche les conflits de noms. Dans un grand projet, il est probable que deux développeurs créent des fonctions getName (). Si l'un crée un ClassName1 :: getName () et que l'autre crée ClassName2 :: getName (), ce n'est pas du tout un problème. Pas de conflit. Ouais méthodes statiques!

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

Il en va de même pour les variables statiques: Exemple: View :: templates_path versus self :: templates_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 faire référence à sa propre variable statique, elle dirait juste self: Exemple: self :: connection;

J'espère que cela aide à clarifier les choses :)

lo_fye
la source
Très bonne réponse. Je veux juste souligner que lorsque vous faites référence à un attribut statique, vous devez utiliser un $signe. Par exempleself::$templates_path
henrywright
30

De ce billet de blog :

  • self fait référence à la classe actuelle
  • self peut être utilisé pour appeler des fonctions statiques et référencer des variables de membres statiques
  • self peut être utilisé à l'intérieur de fonctions statiques
  • self peut également désactiver le comportement polymorphe en contournant le vtable
  • $this fait référence à l'objet courant
  • $this peut être utilisé pour appeler des fonctions statiques
  • $thisne doit pas être utilisé pour appeler des variables de membre statiques. Utilisez selfplutôt.
  • $this ne peut pas être utilisé dans des fonctions statiques
okconfused
la source
26

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()par self::method()n'importe où, quel que soit le cas method()est déclarée statique ou non. Alors, lequel devez-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()affichera toujours «parent», tandis que $this->who()dépendra de la classe de l'objet.

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

Par conséquent, vous ne devez utiliser self que lorsqu'il $thisn'est pas disponible ou lorsque vous ne souhaitez pas autoriser les classes descendantes à remplacer la méthode actuelle.

ramin rostami
la source
22

Dans une définition de classe, $thisfait référence à l'objet actuel, tandis que selffait référence à la classe actuelle.

Il est nécessaire de faire référence à un élément de classe en utilisant selfet de faire référence à 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  
Tarun Singhal
la source
21

Voici un exemple d'utilisation correcte de $ this et self pour les variables membres 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();
?> 
Mohit Bumb
la source
21

Selon http://www.php.net/manual/en/language.oop5.static.php, il n'y en a pas $self. Il n'y a $this, pour faire référence à l'instance actuelle de la classe (l'objet), et self, qui peuvent être utilisés pour faire référence aux membres statiques d'une classe. La différence entre une instance d'objet et une classe entre en jeu ici.

cruizer
la source
9
Suggestion: lisez cette réponse lors d'un déclenchement avec de l'acide.
2015 à 10h08
16

Je crois que la question n'était pas de savoir si vous pouvez appeler le membre statique de la classe en appelant ClassName::staticMember. La question était quelle est la différence entre utiliser self::classmemberet $this->classmember.

Par exemple, les deux exemples suivants fonctionnent sans erreur, que vous utilisiez self::ou$this->

class Person{
    private $name;
    private $address;

    public function __construct($new_name,$new_address){
        $this->name = $new_name;
        $this->address = $new_address;
    }
}

class Person{
    private $name;
    private $address;
    public function __construct($new_name,$new_address){
        self::$name = $new_name;
        self::$address = $new_address;
    }
}
Rotimi
la source
Il est particulièrement amusant que vous commenciez votre réponse par "Je pense que la question n'était pas de savoir si vous pouvez appeler le membre statique de la classe en appelant ClassName :: staticMember. La question était de savoir quelle était la différence entre l'utilisation de self :: classmember et $ this-> classmember" puis vous continuez à ne montrer aucune différence. En fait, vous montrez une instance où les deux options fonctionnent de manière identique. -1
Buttle Butkus
Néanmoins utile. La portée portait sur la résolution et cette partie n'est pas claire dans le manuel php. Je le trouve toujours utile
renoirb
2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun
16

self fait référence à la classe actuelle (dans laquelle elle est appelée),

$thisfait référence à l'objet actuel. Vous pouvez utiliser statique au lieu de self. Voir l'exemple:

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

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

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

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

Sortie: parent enfant

Kabir Hossain
la source
16
  • Le pointeur d'objet $thisvers fait référence à l'objet actuel.
  • La valeur de classe staticfait référence à l'objet actuel.
  • La valeur de classe selffait référence à la classe exacte dans laquelle elle a été définie.
  • La valeur de classe parentfait référence au parent de la classe exacte dans laquelle elle a été définie.

Voir l'exemple suivant qui montre la surcharge.

<?php

class A {

    public static function newStaticClass()
    {
        return new static;
    }

    public static function newSelfClass()
    {
        return new self;
    }

    public function newThisClass()
    {
        return new $this;
    }
}

class B extends A
{
    public function newParentClass()
    {
        return new parent;
    }
}


$b = new B;

var_dump($b::newStaticClass()); // B
var_dump($b::newSelfClass()); // A because self belongs to "A"
var_dump($b->newThisClass()); // B
var_dump($b->newParentClass()); // A


class C extends B
{
    public static function newSelfClass()
    {
        return new self;
    }
}


$c = new C;

var_dump($c::newStaticClass()); // C
var_dump($c::newSelfClass()); // C because self now points to "C" class
var_dump($c->newThisClass()); // C
var_dump($b->newParentClass()); // A because parent was defined *way back* in class "B"

La plupart du temps, vous voulez vous référer à la classe actuelle, c'est pourquoi vous utilisez staticou $this. Cependant, il y a des moments où vous en avez besoin self parce que vous voulez la classe d'origine indépendamment de ce qui la prolonge. (Très, très rarement)

Xeoncross
la source
14

Comme personne ici n'a parlé de performances, voici un petit benchmark que j'ai fait (5.6):

 Name     | Time    | Percent  
----------|---------|---------  
 $this->  | 0.99163 | 106.23%  
 self::   | 0.96912 | 103.82%  
 static:: | 0.93348 | 100%

Ce sont les résultats pour 2 000 000 de runs, et voici le code que j'ai utilisé:

<?php

require '../vendor/autoload.php';

// My small class to do benchmarks
// All it does is looping over every test x times and record the
//   time it takes using `microtime(true)`
// Then, the percentage is calculated, with 100% being the quickest
// Times are being rouned for outputting only, not to calculate the percentages
$b = new Tleb\Benchmark\Benchmark(2000000);

class Foo
{
    public function calling_this()
    {
        $this->called();
    }

    public function calling_self()
    {
        self::called();
    }

    public function calling_static()
    {
        static::called();
    }

    public static function called()
    {
    }
}

$b->add('$this->',  function () { $foo = new Foo; $foo->calling_this(); });
$b->add('self::',   function () { $foo = new Foo; $foo->calling_self(); });
$b->add('static::', function () { $foo = new Foo; $foo->calling_static(); });

$b->run();
tleb
la source
1
L'appel de la fonction no-op 2 000 000 fois dure 1 seconde. Je dois aimer PHP.
rr-
Bon vieux PHP. :) Mais un appel = 0,001 ms. C'est si mauvais?
tleb
Je crois que cela (et des choses similaires) est la raison pour laquelle des choses telles que les ORM semblent lentes à moins que vous ne mettiez en cache des éléments, et les générateurs de sites statiques sont une chose.
rr
2
Il devrait théoriquement prendre 1 cycle d'horloge du processeur, ce qui fait environ 1 / 2e9 s = 0.5 nsces jours-ci
Buddy
Relisez ma réponse. Attention: cela crée aussi la classe . Je ne sais pas pourquoi je n'ai pas utilisé le usemot - clé tbh, mais je n'ai plus PHP pour refaire un benchmark, et je n'ai pas vraiment envie de le réinstaller.
tleb
13

Lorsqu'il selfest utilisé avec l' ::opérateur, il fait référence à la classe actuelle, ce qui peut être fait à la fois dans des contextes statiques et non statiques. $thisfait référence à l'objet lui-même. De plus, il est parfaitement légal d'utiliser $thispour appeler des méthodes statiques (mais pas pour faire référence à des champs).

mrDjouk
la source
8

Je suis tombé sur la même question et la réponse simple est:

  • $this nécessite une instance de la classe
  • self:: ne

Chaque fois que vous utilisez des méthodes statiques ou des attributs statiques et que vous souhaitez les appeler sans avoir un objet de la classe instancié, vous devez les utiliser self:pour les appeler, car $thisil faut toujours créer un objet.

Mike
la source
7

$thisfait référence à l'objet de classe actuel, selffait référence à la classe actuelle (pas d'objet). La classe est le plan directeur de l'objet. Vous définissez donc une classe, mais vous construisez des objets.

En d'autres termes, utilisez self for staticet this for none-static members or methods.

également dans le scénario enfant / parent self / parentest principalement utilisé pour identifier les membres et les méthodes de la classe enfant et parent.

Rakesh Singh
la source
7

De plus, depuis $this::n'a pas encore été discuté.

À titre informatif uniquement, à partir de PHP 5.3 lorsque vous traitez avec des objets instanciés pour obtenir la valeur de portée actuelle, par opposition à l'utilisation static::, vous pouvez également l'utiliser $this::comme tel.

http://ideone.com/7etRHy

class Foo
{
    const NAME = 'Foo';

    //Always Foo::NAME (Foo) due to self
    protected static $staticName = self::NAME;

    public function __construct()
    {
        echo $this::NAME;
    }

    public function getStaticName()
    {
       echo $this::$staticName;
    }
}

class Bar extends Foo
{
    const NAME = 'FooBar';

    /**
     * override getStaticName to output Bar::NAME
     */
    public function getStaticName()
    {
        $this::$staticName = $this::NAME;
        parent::getStaticName();
    }
}

$foo = new Foo; //outputs Foo
$bar = new Bar; //outputs FooBar
$foo->getStaticName(); //outputs Foo
$bar->getStaticName(); //outputs FooBar
$foo->getStaticName(); //outputs FooBar

L'utilisation du code ci-dessus n'est pas une pratique courante ou recommandée, mais vise simplement à illustrer son utilisation et consiste à agir davantage comme un "Le saviez-vous?" en référence à la question de l'affiche originale.

Il représente également l'utilisation $object::CONSTANTpar exemple echo $foo::NAME;de$this::NAME;

fyrye
la source
5

À utiliser selfsi vous souhaitez appeler une méthode d'une classe sans créer d'objet / instance de cette classe, économisant ainsi de la RAM (utilisez parfois self à cet effet). En d'autres termes, il appelle en fait une méthode de manière statique. À utiliser thispour la perspective d'objet.

minhajul
la source
2

Cas 1: l'utilisation selfpeut être utilisée pour les constantes de classe

 classe classA { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}

Si vous voulez l'appeler en dehors de la classe, utilisez classA::POUNDS_TO_KILOGRAMSpour accéder aux constantes

Cas 2: pour les propriétés statiques

class classC {
     fonction publique __construct () { 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}
li bing zhao
la source
1

Selon php.net , il y a trois mots - clés spécifiques dans ce contexte: self, parentet static. Ils sont utilisés pour accéder aux propriétés ou méthodes de l'intérieur de la définition de classe.

$this, d'autre part, est utilisé pour appeler une instance et des méthodes de n'importe quelle classe tant que cette classe est accessible.

Fil
la source
-1

 mot-clé self :: utilisé pour la classe actuelle et utilisé pour accéder aux membres statiques, aux méthodes et aux constantes. Mais dans le cas de $ this, vous ne pouvez pas appeler le membre statique, la méthode et les fonctions.

Vous pouvez utiliser le mot-clé self :: dans une autre classe et accéder aux membres statiques, à la méthode et aux constantes. Quand il sera étendu de la classe parente et même en cas de $ this mot - clé. Vous pouvez accéder aux membres non statiques, à la méthode et à la fonction dans une autre classe lorsqu'elle sera étendue à partir de la classe parente.

Le code donné ci-dessous est un exemple de self :: et $ this mot - clé. Copiez et collez simplement le code dans votre fichier de code et voyez le résultat.

class cars{
    var $doors=4;   
    static $car_wheel=4;

  public function car_features(){
    echo $this->doors." Doors <br>";
    echo self::$car_wheel." Wheels <br>"; 
  }
}

class spec extends cars{
    function car_spec(){
        print(self::$car_wheel." Doors <br>");
        print($this->doors." Wheels <br>");
    }
}

/********Parent class output*********/

$car = new cars;
print_r($car->car_features());

echo "------------------------<br>";

/********Extend class from another class output**********/


$car_spec_show=new spec;

print($car_spec_show->car_spec());
Deepak Syal
la source