Pregunta ¿Cuándo usar self over $ this?


En PHP 5, ¿cuál es la diferencia entre usar self y $this?

¿Cuándo es apropiado cada uno?


1775
2017-09-30 06:23


origen


Respuestas:


Respuesta corta

Utilizar $this para referirse a la corriente   objeto. Utilizar self para referirse al   clase actual. En otras palabras, use    $this->member para miembros no estáticos,   utilizar self::$member para miembros estáticos.

Respuesta completa

Aquí hay un ejemplo de correcto uso de $this y self para variables de miembro no estáticas y estáticas:

<?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();
?>

Aquí hay un ejemplo de incorrecto uso de $this y self para variables de miembro no estáticas y estáticas:

<?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();
?>

Aquí hay un ejemplo de polimorfismo con $this para funciones miembro:

<?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();
?>

Aquí hay un ejemplo de suprimir el comportamiento polimórfico mediante el uso self para funciones miembro:

<?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();
?>

La idea es que $this->foo() llama al foo() función de miembro de lo que sea> es el tipo exacto del objeto actual. Si el objeto es de type X, por lo tanto> llama X::foo(). Si el objeto es de type Y, llama Y::foo(). Pero con> self :: foo (), X::foo() siempre se llama.

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

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


1508
2017-09-30 06:29



La palabra clave self does NO refiérase simplemente a la 'clase actual', al menos no de una manera que lo restrinja a miembros estáticos. En el contexto de un miembro no estático, self también proporciona una forma de eludir el vtable (ver wiki en vtable) para el objeto actual. Del mismo modo que puedes usar parent::methodName() para llamar a la versión de los padres de una función, para que pueda llamar self::methodName() llamar a las clases actuales la implementación de un método.

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();

Esto dará como resultado:

Hola, soy Ludwig el friki
     Adiós de Ludwig la persona

sayHello() usa el $this puntero, por lo que se invoca el vtable para llamar Geek::getTitle(). sayGoodbye() usos self::getTitle(), entonces el vtable no se usa, y Person::getTitle() se llama. En ambos casos, estamos tratando con el método de un objeto instanciado, y tenemos acceso a la $this puntero dentro de las funciones llamadas.


710
2017-07-27 18:00



NO UTILICE self::, utilizar static::

Hay otro aspecto de sí mismo que vale la pena mencionar. Molesto self:: se refiere al alcance en el punto de definición no en el punto de ejecución. Considere esta clase simple con dos métodos:

class Person
{

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

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

}

Si llamamos Person::status() veremos "La persona está viva". Ahora considere lo que sucede cuando hacemos una clase que hereda de esto:

class Deceased extends Person
{

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

}

Vocación Deceased::status() esperaríamos ver "La persona ha fallecido", sin embargo, lo que vemos es "Persona está viva", ya que el alcance contiene la definición del método original cuando se llama a self::getStatus() Fue definido.

PHP 5.3 tiene una solución. el static:: El operador de resolución implementa "enlace estático tardío", que es una forma elegante de decir que está vinculado al alcance de la clase llamada. Cambiar la línea en status() a static::getStatus() y los resultados son lo que esperarías En versiones anteriores de PHP tendrá que encontrar un kludge para hacer esto.

Ver Documentación PHP

Entonces, para responder la pregunta no como se le preguntó ...

$this-> se refiere al objeto actual (una instancia de una clase), mientras que static::se refiere a una clase


428
2017-07-24 15:08



Para realmente entender de lo que estamos hablando cuando hablamos de self versus $this, necesitamos profundizar en lo que está sucediendo en un nivel conceptual y práctico. Realmente no siento que ninguna de las respuestas lo haga de manera apropiada, así que aquí está mi intento.

Comencemos hablando sobre qué clase y un objeto es.

Clases y objetos, conceptualmente

Y qué es un clase? Mucha gente lo define como un cianotipo o una modelo para un objeto. De hecho, puedes leer más Acerca de las clases en PHP aquí. Y hasta cierto punto eso es lo que realmente es. Veamos una clase:

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

Como puede ver, hay una propiedad en esa clase llamada $name y un método (función) llamado sayHello().

Sus muy importante tener en cuenta que el clase es una estructura estática Lo que significa que la clase PersonUna vez que se define, siempre es igual donde sea que se mire.

Un objeto por otro lado es lo que se llama ejemplo de una clase. Lo que eso significa es que tomamos el "plano" de la clase y lo usamos para hacer una copia dinámica. Esta copia ahora está vinculada específicamente a la variable en la que está almacenada. Por lo tanto, cualquier cambio en un ejemplo es local para esa instancia.

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

Creamos nuevos instancias de una clase usando el new operador.

Por lo tanto, decimos que una Clase es una estructura global, y un Objeto es una estructura local. No te preocupes por eso divertido -> sintaxis, vamos a entrar en eso en un momento.

Otra cosa de la que deberíamos hablar, es que podemos comprobar si una instancia es un instanceof una clase particular: $bob instanceof Person que devuelve un valor booleano si $bob instancia fue hecha usando el Person clase, o un niño de Person.

Estado definidor

Así que profundicemos un poco en lo que realmente contiene una clase. Hay 5 tipos de "cosas" que una clase contiene:

  1. Propiedades - Piense en estas como variables que contendrá cada instancia.

    class Foo {
        public $bar = 1;
    }
    
  2. Propiedades estáticas - Piense en estas como variables que se comparten en el nivel de clase. Lo que significa que nunca son copiados por cada instancia.

    class Foo {
        public static $bar = 1;
    }
    
  3. Métodos - Estas son funciones que cada instancia contendrá (y operará en instancias).

    class Foo {
        public function bar() {}
    }
    
  4. Métodos estáticos - Estas son funciones que se comparten en toda la clase. Ellas hacen no operar en instancias, sino en las propiedades estáticas solamente.

    class Foo {
        public static function bar() {}
    }
    
  5. Constantes - Constantes resueltas en clase. No profundizar más aquí, sino agregar para completar:

    class Foo {
        const BAR = 1;
    }
    

Básicamente, almacenamos información en el contenedor de clases y objetos usando "pistas" sobre estático que identifican si la información es compartida (y por lo tanto estática) o no (y por lo tanto dinámica).

Estado y métodos

Dentro de un método, la instancia de un objeto está representada por $thisvariable. El estado actual de ese objeto está allí, y mutar (cambiar) cualquier propiedad dará como resultado un cambio en esa instancia (pero no en otras).

Si un método se llama estáticamente, el $this variable no está definido. Esto se debe a que no hay ninguna instancia asociada con una llamada estática.

Lo interesante aquí es cómo se hacen las llamadas estáticas. Entonces, hablemos sobre cómo accedemos al estado:

Accediendo al estado

Entonces, ahora que hemos almacenado ese estado, necesitamos acceder a él. Esto puede ser un poco complicado (o camino más que un poco), así que dividamos esto en dos puntos de vista: desde afuera de una instancia / clase (por ejemplo desde una llamada a función normal, o desde el alcance global), y dentro de una instancia / clase (desde dentro de un método en el objeto).

Desde afuera de una instancia / clase

Desde el exterior de una instancia / clase, nuestras reglas son bastante simples y predecibles. Tenemos dos operadores, y cada uno nos dice de inmediato si estamos tratando con una instancia o una clase estática:

  • -> - objeto-operador - Esto siempre se usa cuando estamos accediendo a una instancia.

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

    Es importante tener en cuenta que llamar Person->foo no tiene sentido (ya que Person es una clase, no una instancia). Por lo tanto, eso es un error de análisis.

  • :: - operador de resolución de alcance - Esto siempre se usa para acceder a una propiedad o método estático de clase.

    echo Foo::bar()
    

    Además, podemos llamar a un método estático en un objeto de la misma manera:

    echo $foo::bar()
    

    Sus extremadamente importante tener en cuenta que cuando hacemos esto desde afuera, la instancia del objeto está oculta bar() método. Lo que significa que es exactamente lo mismo que ejecutar:

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

Por lo tanto, $this no está definido en la llamada estática.

Desde el interior de una instancia / clase

Las cosas cambian un poco aquí. Se utilizan los mismos operadores, pero su significado se vuelve significativamente borroso.

los objeto-operador  -> todavía se usa para hacer llamadas al estado de la instancia del objeto.

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

Llamando al bar() método en $foo (una instancia de Foo) utilizando el objeto-operador: $foo->bar() dará como resultado la versión de la instancia de $a.

Así que así es como esperamos.

El significado de la :: operador aunque cambios. Depende del contexto de la llamada a la función actual:

  • Dentro de un contexto estático

    Dentro de un contexto estático, cualquier llamada realizada usando :: también será estático. Veamos un ejemplo:

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

    Vocación Foo::bar() llamará al baz() método estáticamente, y por lo tanto $this será no ser poblado Vale la pena señalar que en las versiones recientes de PHP (5.3+) esto disparará una E_STRICT error, porque estamos llamando a métodos no estáticos estáticamente.

  • Dentro de un contexto de instancia

    Dentro de un contexto de instancia, por otro lado, las llamadas realizadas usando :: depende del receptor de la llamada (el método que estamos llamando). Si el método se define como static, entonces usará una llamada estática. Si no es así, reenviará la información de la instancia.

    Entonces, mirando el código de arriba, llamando $foo->bar() regresará true, ya que la llamada "estática" ocurre dentro de un contexto de instancia.

¿Tener sentido? No lo creo Es confuso.

Palabras clave abreviadas

Debido a que vincular todo junto usando nombres de clase es bastante sucio, PHP proporciona 3 palabras clave básicas de "acceso directo" para facilitar la resolución del alcance.

  • self - Esto se refiere al nombre de clase actual. Asi que self::baz() es lo mismo que Foo::baz() dentro de Foo clase (cualquier método en él).

  • parent - Esto se refiere al padre de la clase actual.

  • static - Esto se refiere a la clase llamada. Gracias a la herencia, las clases secundarias pueden anular los métodos y las propiedades estáticas. Entonces llamándolos usando static en lugar de un nombre de clase, nos permite resolver de dónde vino la llamada, en lugar del nivel actual.

Ejemplos

La forma más fácil de entender esto es comenzar a buscar algunos ejemplos. Escojamos una clase:

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();
    }
}

Ahora, también estamos viendo herencia aquí. Ignore por un momento que este es un modelo de objeto malo, pero echemos un vistazo a lo que sucede cuando jugamos con esto:

$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

Entonces, el contador de ID se comparte entre las instancias y los niños (porque estamos usando self para acceder a ella Si usamos static, podríamos anularlo en una clase infantil).

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

Tenga en cuenta que estamos ejecutando el Person::getName()  ejemplo método todo el tiempo. Pero estamos usando el parent::getName() para hacerlo en uno de los casos (el caso del niño). Esto es lo que hace que este enfoque sea poderoso.

Palabra de precaución n. ° 1

Tenga en cuenta que el contexto de llamada es lo que determina si se utiliza una instancia. Por lo tanto:

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

No es siempre cierto.

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

Ahora es De Verdad raro aquí. Estamos llamando a una clase diferente, pero el $this eso se pasa a la Foo::isFoo() método es la instancia de $bar.

Esto puede causar todo tipo de errores y WTF-ery conceptual. Así que recomiendo evitar el :: Operador desde dentro métodos de instancia en cualquier cosa excepto esas tres palabras clave "atajos" virtuales (static, selfy parent)

Palabra de Precaución # 2

Tenga en cuenta que todos comparten las propiedades y los métodos estáticos. Eso los hace básicamente variables globales. Con todos los mismos problemas que vienen con los globales. Por lo tanto, dudaría mucho en almacenar información en métodos / propiedades estáticos a menos que se sienta cómodo con que sea verdaderamente global.

Palabra de precaución n. ° 3

En general, querrá usar lo que se conoce como Enlace estático tardío mediante el uso de static en lugar de self. Pero tenga en cuenta que no son la misma cosa, por lo que dice "siempre use static en lugar de self es realmente miope En cambio, deténgase y piense acerca de la llamada que desea hacer y piense si desea que las clases para niños puedan anular esa estático resuelto llamada.

TL / DR

Lástima, vuelve y léelo. Puede ser demasiado largo, pero es tan largo porque este es un tema complejo

TL / DR # 2

Está bien. En breve, self se usa para referencia el nombre de clase actualdentro de una clase, donde como $this se refiere al objeto actual ejemplo. Tenga en cuenta que self es un atajo de copiar / pegar. Puedes reemplazarlo de manera segura con tu nombre de clase, y funcionará bien. Pero $this es una variable dinámica que no se puede determinar antes de tiempo (y puede que ni siquiera sea su clase).

TL / DR # 3

Si se usa el objeto operador (->), entonces tú siempre Sé que estás tratando con una instancia. Si se usa el operador de resolución de alcance (::), necesita más información sobre el contexto (¿estamos ya en un contexto de objeto? ¿Estamos fuera de un objeto ?, etc.).


228
2018-06-10 15:21



self (no $ self) se refiere al tipo de clase, donde como $this se refiere a la corriente ejemplo de la clase. self es para usar en funciones miembro estáticas para permitirle acceder a las variables de miembros estáticos. $this se usa en funciones miembro no estáticas, y es una referencia a la instancia de la clase en la que se llamó a la función miembro.

Porque this es un objeto, lo usas como: $this->member

Porque self no es un objeto, es básicamente un tipo que se refiere automáticamente a la clase actual, lo usas como: self::member


109
2017-09-30 07:26



$this-> se usa para referirse a una instancia específica de las variables de una clase (variables miembro) o métodos.

Example: 
$derek = new Person();

$ derek ahora es una instancia específica de Person. Cada persona tiene un first_name y un last_name, pero $ derek tiene un first_name y un last_name específicos (Derek Martin). Dentro de la instancia de $ derek, podemos referirnos a ellos como $ this-> first_name y $ this-> last_name

ClassName :: se utiliza para referirse a ese tipo de clase, y sus variables estáticas, métodos estáticos. Si ayuda, puede reemplazar mentalmente la palabra "estático" por "compartido". Debido a que son compartidos, no pueden referirse a $ this, que se refiere a una instancia específica (no compartida). Las variables estáticas (es decir, $ db_connection estática) se pueden compartir entre todas las instancias de un tipo de objeto. Por ejemplo, todos los objetos de la base de datos comparten una única conexión ($ conexión estática).

Ejemplo de variables estáticas: Supongamos que tenemos una clase de base de datos con una variable de miembro único: static $ num_connections; Ahora, pon esto en el constructor:

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

Así como los objetos tienen constructores, también tienen destructores, que se ejecutan cuando el objeto muere o está desarmado:

function __destruct()
{
    $num_connections--;
}

Cada vez que creamos una nueva instancia, aumentará nuestro contador de conexión en uno. Cada vez que destruimos o dejamos de usar una instancia, disminuirá el contador de conexión en uno. De esta forma, podemos monitorear el número de instancias del objeto de base de datos que tenemos en uso con:

echo DB::num_connections;

Como $ num_connections es estática (compartida), reflejará la cantidad total de objetos activos de la base de datos. Es posible que haya visto esta técnica utilizada para compartir conexiones de bases de datos entre todas las instancias de una clase de base de datos. Esto se hace porque la creación de la conexión de la base de datos lleva mucho tiempo, por lo que es mejor crear solo uno y compartirlo (esto se denomina Patrón de Singleton).

Los métodos estáticos (es decir, public static View :: format_phone_number ($ digits)) se pueden usar SIN crear una instancia de uno de esos objetos (es decir, no se refieren internamente a $ this).

Ejemplo de método estático:

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

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

Como puede ver, la función estática pública prettyName no sabe nada sobre el objeto. Simplemente está trabajando con los parámetros que ingresas, como una función normal que no es parte de un objeto. ¿Por qué molestarse, entonces, si pudiéramos simplemente no tenerlo como parte del objeto?

  1. Primero, asociar funciones a objetos lo ayuda a mantener las cosas organizadas, para que sepa dónde encontrarlas.
  2. En segundo lugar, evita conflictos de nombres. En un proyecto grande, es probable que tengas dos desarrolladores que creen funciones getName (). Si uno crea un ClassName1 :: getName (), y el otro crea ClassName2 :: getName (), no hay ningún problema. No conflicto. ¡Yay métodos estáticos!

YO:: Si estás codificando fuera de el objeto que tiene el método estático al que desea hacer referencia, debe llamarlo usando el nombre del objeto View :: format_phone_number ($ phone_number); Si estás codificando dentro el objeto que tiene el método estático al que desea hacer referencia, puede ya sea use el nombre del objeto View :: format_phone_number ($ pn), O puede usar el acceso directo self :: format_phone_number ($ pn)

Lo mismo ocurre con las variables estáticas: Ejemplo: Ver :: templates_path versus self :: templates_path

Dentro de la clase DB, si nos refiriéramos a un método estático de algún otro objeto, usaríamos el nombre del objeto: Ejemplo: Session :: getUsersOnline ();

Pero si la clase DB quisiera referirse a su propia variable estática, simplemente diría self: Ejemplo: self :: conexión;

Espero que ayude a aclarar las cosas :)


93
2017-10-22 17:52



De esta publicación en el blog:

  • self se refiere a la clase actual
  • self se puede usar para llamar funciones estáticas y variables de miembros estáticos de referencia
  • self se puede usar dentro de funciones estáticas
  • self también puede desactivar el comportamiento polimórfico al eludir el vtable
  • $this se refiere al objeto actual
  • $this se puede usar para llamar funciones estáticas
  • $this no debe usarse para llamar a variables miembro estáticas. Utilizar self en lugar.
  • $this no se puede usar dentro de funciones estáticas

27
2018-05-10 12:00



En PHP, utiliza la palabra clave self para acceder a propiedades y métodos estáticos.

El problema es que puedes reemplazar $this->method() con self::method()en cualquier lugar, independientemente de si method() se declara estático o no. Entonces, ¿cuál debería usar?

Considera este código:

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();

En este ejemplo, self::who() siempre dará salida 'padre', mientras que $this->who() dependerá de qué clase tenga el objeto.

Ahora podemos ver que self se refiere a la clase en la que se llama, mientras que $this se refiere a clase del objeto actual.

Entonces, debes usar solo solo cuando $this no está disponible, o cuando no desea permitir que las clases descendientes sobrescriban el método actual.


23
2017-12-29 13:20



Dentro de una definición de clase, $ esto se refiere al objeto actual, mientras que self se refiere a la clase actual.

Es necesario referirse a un elemento de clase utilizando self y hacer referencia a un elemento de objeto usando $ 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



Aquí hay un ejemplo del uso correcto de $ this y self para no estático   y variables de miembros estáticos:

<?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



De acuerdo a http://www.php.net/manual/en/language.oop5.static.php no hay $self. Solo hay $this, para referirse a la instancia actual de la clase (el objeto) y a uno mismo, que se puede usar para referirse a miembros estáticos de una clase. La diferencia entre una instancia de objeto y una clase entra en juego aquí.


16
2017-09-30 06:29