¿Cuándo usar self sobre $ this?

1997

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

¿Cuándo es apropiado cada uno?

Casey Watson
fuente
posible duplicado de Nuevo self versus nuevo static
Orangepill
Voy a preguntar cuál es la diferencia entre: cont A; $ this-> A and self :: A
timmz

Respuestas:

1728

Respuesta corta

Use $thispara referirse al objeto actual. Use selfpara referirse a la clase actual. En otras palabras, use $this->memberpara miembros no estáticos, use self::$memberpara miembros estáticos.

Respuesta completa

Aquí hay un ejemplo del uso correcto de $thisy selfpara variables 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 uso incorrecto de $thisy selfpara variables 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 $thisfunciones 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 supresión del comportamiento polimórfico mediante el uso selfde 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 a la foo()función miembro de lo que sea el tipo exacto del objeto actual. Si el objeto es de type X, así 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

John Millikin
fuente
330
Esta respuesta es demasiado simplista. Como se señaló en otras respuestas, selfse usa con el operador de resolución de alcance ::para referirse a la clase actual; Esto se puede hacer tanto en contextos estáticos como no estáticos. Además, es perfectamente legal usarlo $thispara llamar a métodos estáticos (pero no para hacer referencia a campos).
Artefacto
50
También considere usar static :: en lugar de :: self si tiene 5.3+. De lo contrario, puede causarle innumerables dolores de cabeza, vea mi respuesta a continuación para saber por qué.
Sqoo
25
-1. Esta respuesta es engañosa, lea las otras respuestas para obtener más información.
Pacerier
66
Puede estar demasiado simplificado, pero respondió a mi pregunta de nivel básico sin hacer explotar mi cabeza. Obtuve más información que encontré útil más abajo, pero por ahora solo estaba tratando de descubrir por qué golpeé mis atributos de clase con $ this-> attrib y las constantes de clase con self :: constant. Esto me ayudó a entender eso mejor
MydKnight
¿Qué hay de $this::?
James
742

La palabra clave self NO se refiere simplemente a la 'clase actual', al menos no de una manera que lo restrinja a miembros estáticos. Dentro del contexto de un miembro no estático, selftambién proporciona una forma de evitar el vtable ( ver wiki en vtable ) para el objeto actual. Al igual que puede usar parent::methodName()para llamar a la versión principal de una función, también puede llamar self::methodName()para llamar a la implementación de un método de las clases actuales.

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 generará:

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

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

nbeagle
fuente
3
Esta respuesta sería aún mejor si comenzaras con una regla general en lugar de una excepción. Es una cuestión de estilo, no de experiencia técnica. Este es el mejor ejemplo que he visto de la diferencia entre self :: y $ this->, pero es una pena ocultarlo al refutar primero una noción.
adjwilli
3
@adjwilli: ¿Por qué es ese mal estilo? ¿No aumenta la conciencia si la expectativa (tesis) de la OP se desaprueba primero (antítesis) y luego la explicación se da como síntesis?
Hakre
1
Encuentro "clase actual" realmente problemático. Como esa combinación de palabras puede entenderse como "la clase donde selfse ubica" / "la definición de clase, es una parte literal de" así como "la clase del objeto" (que en realidad sería static).
Jakumi
¿Qué hay de $this::?
James
1
@ James: no hay una buena razón para usar $this::; Todos los casos posibles ya están cubiertos por las sintaxis más utilizadas. Dependiendo de lo que quiere decir, el uso $this->, self::o static::.
ToolmakerSteve
460

NO USE self::, usestatic::

Hay otro aspecto de self :: que vale la pena mencionar. Molestamente se self::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";
    }

}

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

PHP 5.3 tiene una solución. el static::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. Cambie la línea status()a static::getStatus()y los resultados son lo que esperaría. En versiones anteriores de PHP, tendrá que encontrar un kludge para hacer esto.

Ver documentación de PHP

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

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

Sqoo
fuente
66
¿Qué pasa con las constantes de clase?
Kevin Bond el
53
"Llamando fallecido :: estado () esperaríamos ver" La persona ha fallecido "". No. Esta es una llamada a función estática, por lo que no hay polimorfismo involucrado.
cquezel
2
De todos los defectos de PHP, por mi parte, no creo que esto sea una locura en absoluto. ¿De qué otra forma permitirían a los codificadores designar métodos en la clase actual (en lugar de buscarlos en la tabla)? Si lo hubieran nombrado de manera diferente (tal vez con guiones bajos), las personas que desean esta característica lo criticarían por ser feo. De lo contrario, sea cual sea el nombre sensato que puedan usar, parece que siempre habrá personas fácilmente confundidas que lo criticarán por ser un comportamiento "loco", probablemente ajeno a cómo funciona el envío de métodos.
TNE
2
El ejemplo me parece confuso: veo el getStatusmétodo como uno que llamaría para una instancia de clase, no para una clase.
Jānis Elmeris
1
@Sqoo: decir "NO USE self ::, use static ::" es un punto extraño: esas no son deliberadamente la misma operación. Creo que el punto que realmente está diciendo es "es más claro si usa el nombre de clase real 'MyClass ::', en lugar de 'self ::' . Es decir, si desea el comportamiento de self::, puede obtener eso, menos confusamente, mediante el uso del nombre de clase específico, por ejemplo MyClass::.
ToolmakerSteve
248

Para comprender realmente de qué estamos hablando cuando hablamos de selfversus $this, necesitamos profundizar en lo que sucede a nivel conceptual y práctico. Realmente no siento que ninguna de las respuestas haga esto apropiadamente, así que aquí está mi intento.

Comencemos hablando de qué es una clase y un objeto .

Clases y objetos, conceptualmente

Entonces, ¿qué es una clase ? Mucha gente lo define como un plano o una plantilla para un objeto. De hecho, puede leer más sobre 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 $namey un método (función) llamado sayHello().

Es muy importante tener en cuenta que la clase es una estructura estática. Lo que significa que la clase Person, una vez definida, siempre es la misma en todas partes donde la miras.

Un objeto por otro lado es lo que se llama una instancia 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 una instancia es local para esa instancia.

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

Creamos nuevas instancias de una clase usando el newoperador.

Por lo tanto, decimos que una Clase es una estructura global, y un Objeto es una estructura local. No se preocupe por esa ->sintaxis divertida , vamos a entrar en eso en un momento.

Otra cosa de la que deberíamos hablar es que podemos verificar si una instancia es una instanceofclase particular: lo $bob instanceof Personque devuelve un valor booleano si la $bobinstancia se realizó utilizando la Personclase o un hijo de Person.

Estado definitorio

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

  1. Propiedades : piense en ellas como variables que contendrá cada instancia.

    class Foo {
        public $bar = 1;
    }
  2. Propiedades estáticas : piense en estas como variables que se comparten a nivel de clase. Lo que significa que nunca se copian por cada instancia.

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

    class Foo {
        public function bar() {}
    }
  4. Métodos estáticos : son funciones que se comparten en toda la clase. Ellos no operan en los casos, pero en cambio en las propiedades estáticas solamente.

    class Foo {
        public static function bar() {}
    }
  5. Constantes : constantes resueltas por clase. No profundizando aquí, pero agregando para completar:

    class Foo {
        const BAR = 1;
    }

Básicamente, estamos almacenando información sobre la clase y el contenedor de objetos usando "pistas" sobre estática 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 representa la instancia de un objeto $this. El estado actual de ese objeto está allí, y la mutación (cambio) de cualquier propiedad dará como resultado un cambio en esa instancia (pero no en otras).

Si un método se llama estáticamente, la $thisvariable no está definida . Esto se debe a que no hay una 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:

Estado de acceso

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

Desde fuera 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:

  • ->- object-operator : esto siempre se usa cuando accedemos a una instancia.

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

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

  • ::- scope-resolution-operator : siempre se usa para acceder a una propiedad o método estático de la Clase.

    echo Foo::bar()

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

    echo $foo::bar()

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

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

Por lo tanto, $thisno 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.

El operador de objeto -> todavía se utiliza para realizar llamadas al estado de instancia del objeto.

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

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

Así es como esperamos.

::Aunque el significado del operador cambia. 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 con ::también será estática. Veamos un ejemplo:

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

    La llamada Foo::bar()llamará al baz()método de forma estática y, por $thislo tanto , no se completará. Vale la pena señalar que en versiones recientes de PHP (5.3+) esto provocará un E_STRICTerror, porque estamos llamando a métodos no estáticos estáticamente.

  • Dentro de un contexto de instancia

    Por otro lado, dentro de un contexto de instancia, las llamadas realizadas ::dependen del receptor de la llamada (el método al que estamos llamando). Si el método se define como static, utilizará una llamada estática. Si no es así, reenviará la información de la instancia.

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

¿Tener sentido? No lo creo. Es confuso.

Palabras clave de atajo

Debido a que unir todo 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 la clase actual. Entonces self::baz()es lo mismo que Foo::baz()dentro de la Fooclase (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 métodos y propiedades estáticas. Entonces, llamarlos usando en staticlugar 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 mirar algunos ejemplos. Vamos a elegir 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í. Ignora por un momento que este es un modelo de objeto malo, pero veamos qué 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

Por lo tanto, el contador de ID se comparte entre las instancias y los elementos secundarios (porque lo estamos utilizando selfpara acceder a él. Si lo utilizáramos static, podríamos anularlo en una clase secundaria).

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

Tenga en cuenta que estamos ejecutando el método de Person::getName() instancia cada vez. Pero estamos usando el parent::getName()para hacerlo en uno de los casos (el caso secundario). Esto es lo que hace que este enfoque sea poderoso.

Palabra de precaució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 siempre es verdad.

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

Ahora es realmente raro aquí. Estamos llamando a una clase diferente, pero la $thisque se pasa al Foo::isFoo()método es la instancia de $bar.

Esto puede causar todo tipo de errores y errores conceptuales de WTF. Así que yo recomiendo evitando el ::operador desde el interior de los métodos de instancia en cualquier cosa excepto aquellas tres palabras clave virtuales "atajo" ( static, selfy parent).

Palabra de precaución # 2

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

Palabra de precaución # 3

En general, querrá usar lo que se conoce como enlace estático tardío utilizando en staticlugar de self. Pero tenga en cuenta que no son lo mismo, por lo que decir "siempre usar en staticlugar de selfes realmente miope. En cambio, deténgase y piense en la llamada que desea hacer y piense si desea que las clases secundarias puedan anular esa estática resuelta 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 resumen, selfse utiliza para hacer referencia al nombre de la clase actual dentro de una clase, donde se $thisrefiere a la instancia del objeto actual . Tenga en cuenta que selfes un atajo de copiar / pegar. Puede reemplazarlo con seguridad con el nombre de su clase, y funcionará bien. Pero $thises una variable dinámica que no se puede determinar con anticipación (y puede que ni siquiera sea su clase).

TL / DR # 3

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

ircmaxell
fuente
1
Palabra de precaución # 1: $ esto no se definirá al llamar a un método estático: 3v4l.org/9kr0e
Mark Achée
Bueno ... $thisno se definirá si sigue "Estándares estrictos" y no llama a métodos estáticos que no están definidos como estáticos. Veo el resultado que explicaste aquí: 3v4l.org/WeHVM De acuerdo, realmente extraño.
Mark Achée
2
Después de leer la larga descripción por completo, me sentí perezosa al desplazarme hacia arriba nuevamente para votarla. Solo bromeé, lo voté: D. Gracias esto es muy útil.
Mr_Green
3
Sería bueno agregar una explicación clara sobre la diferencia entre self :: $ property y self :: property; Creo que eso también es bastante confuso
Tommaso Barbugli
1
WoC # 1 se comporta de manera diferente desde PHP 7. Como Foo::isFoo()se llama estáticamente, $thisno se definirá. Ese es un comportamiento más intuitivo en mi opinión. - Se da otro resultado diferente si Barse extendiera desde Foo. Entonces la llamada Foo::isFoo()estaría realmente dentro del contexto de la instancia (no específica de PHP7).
Kontrollfreak
117

self(no $ self) se refiere al tipo de clase, donde se $thisrefiere a la instancia actual de la clase. selfse usa en funciones miembro estáticas para permitirle acceder a variables miembro estáticas. $thisse 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 thises un objeto, lo usas como:$this->member

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

MrZebra
fuente
97

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

Example: 
$derek = new Person();

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

ClassName :: se usa para referirse a ese tipo de clase, y sus variables estáticas, métodos estáticos. Si ayuda, puede reemplazar mentalmente la palabra "estática" con "compartida". 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 sola variable miembro: 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 se desarma:

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 manera, 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ático (compartido), reflejará el número total de objetos de base de datos activos. 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 una y compartirla (esto se denomina Patrón Singleton).

Los métodos estáticos (es decir, vista estática pública :: formato_número_de_teléfono ($ dígitos)) se pueden usar SIN primero instanciar 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 pasa, como una función normal que no es parte de un objeto. ¿Por qué molestarse, entonces, si no podríamos tenerlo como parte del objeto?

  1. Primero, adjuntar funciones a los objetos lo ayuda a mantener las cosas organizadas, para que sepa dónde encontrarlas.
  2. En segundo lugar, evita conflictos de nombres. En un gran proyecto, es probable que dos desarrolladores 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!

SELF :: Si está codificando fuera del objeto que tiene el método estático al que desea referirse, debe llamarlo usando el nombre del objeto View :: format_phone_number ($ phone_number); Si está codificando en el interior del objeto que tiene el método estático que desea hacer referencia a, puede o bien utilizar el nombre Vista :: format_phone_number del objeto ($ pn), o puede utilizar el mismo :: format_phone_number ($ pn) de acceso directo

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

Dentro de la clase DB, si nos referié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, solo diría self: Ejemplo: self :: connection;

Espero que ayude a aclarar las cosas :)

lo_fye
fuente
Gran respuesta. Solo quiero señalar que, cuando se refiere a un atributo estático, debe usar un $signo. Por ejemploself::$templates_path
henrywright
30

De esta publicación de blog :

  • self se refiere a la clase actual
  • self se puede usar para llamar a funciones estáticas y variables de miembro estáticas de referencia
  • self se puede usar dentro de funciones estáticas
  • self También puede desactivar el comportamiento polimórfico al pasar por alto la vtable
  • $this se refiere al objeto actual
  • $this se puede usar para llamar a funciones estáticas
  • $thisno debe usarse para llamar a variables miembro estáticas. Usar en su selflugar.
  • $this no se puede usar dentro de funciones estáticas
okconfused
fuente
26

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

El problema es que puede reemplazarlo $this->method()en self::method()cualquier lugar, independientemente de si method()se declara estático o no. Entonces, ¿cuál deberías 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 generará 'padre', mientras $this->who()que dependerá de qué clase tenga el objeto.

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

Por lo tanto, debe usar self solo cuando $thisno esté disponible o cuando no desee permitir que las clases descendientes sobrescriban el método actual.

ramin rostami
fuente
22

Dentro de una definición de clase, se $thisrefiere al objeto actual, mientras que se selfrefiere a la clase actual.

Es necesario hacer referencia a un elemento de clase usando 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  
Tarun Singhal
fuente
21

Aquí hay un ejemplo del uso correcto de $ this y self para variables 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();
?> 
Mohit Bumb
fuente
21

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

crucero
fuente
99
Sugerencia: Lea esta respuesta al tropezar con ácido.
a20
16

Creo que la pregunta no era si se puede llamar al miembro estático de la clase llamando ClassName::staticMember. La pregunta era cuál es la diferencia entre usar self::classmembery $this->classmember.

Por ejemplo, los dos ejemplos siguientes funcionan sin ningún error, ya sea que use self::o$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
fuente
Es especialmente divertido que comiences tu respuesta con "Creo que la pregunta no era si puedes llamar al miembro estático de la clase llamando a ClassName :: staticMember. La pregunta era cuál es la diferencia entre usar self :: classmember y $ this-> classmember" y luego procedes a no mostrar ninguna diferencia. De hecho, muestra una instancia de donde las dos opciones funcionan de manera idéntica. -1
Buttle Butkus
Sin embargo útil. El alcance era sobre la resolución y esta parte no está clara en el manual de php. Todavía lo encuentro útil
renoirb el
2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun
16

self hace referencia a la clase actual (en la que se llama),

$thisse refiere al objeto actual. Puedes usar static en lugar de self. Mira el ejemplo:

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

Salida: padre hijo

Kabir Hossain
fuente
16
  • El puntero del objeto se $thisrefiere al objeto actual.
  • El valor de la clase se staticrefiere al objeto actual.
  • El valor selfde la clase se refiere a la clase exacta en la que se definió.
  • El valor de la clase se parentrefiere al padre de la clase exacta en la que se definió.

Vea el siguiente ejemplo que muestra sobrecarga.

<?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 mayoría de las veces desea referirse a la clase actual, por eso utiliza statico $this. Sin embargo, hay momentos en los que necesita self porque desea la clase original independientemente de lo que la extienda. (Muy, muy raramente)

Xeoncross
fuente
14

Como nadie aquí habló de actuaciones, aquí hay un pequeño punto de referencia que hice (5.6):

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

Esos son los resultados de 2 000 000 ejecuciones, y aquí está el código que utilicé:

<?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
fuente
1
Llamar a la función no operativa 2 000 000 veces dura 1 s. Tengo que amar PHP.
rr-
Buen viejo PHP. :) Pero una llamada = 0.001ms. ¿Es tan malo?
Tleb
Creo que esto (y otras cosas similares) es la razón por la cual las cosas como ORM se sienten lentas a menos que almacene cosas en caché, y los generadores de sitios estáticos son una cosa.
rr-
2
Teóricamente debería tomar 1 ciclo de reloj del procesador, lo que hace alrededor de 1 / 2e9 s = 0.5 nsestos días
Buddy
Solo vuelve a leer mi respuesta. Tenga cuidado: también crea la clase . No sé por qué no useusé la palabra clave tbh, pero ya no tengo PHP para rehacer un punto de referencia, y realmente no tengo ganas de reinstalarlo.
tleb
13

Cuando selfse usa con el ::operador, se refiere a la clase actual, que se puede hacer tanto en contextos estáticos como no estáticos. $thisse refiere al objeto mismo. Además, es perfectamente legal usarlo $thispara llamar a métodos estáticos (pero no para referirse a los campos).

mrDjouk
fuente
8

Me encontré con la misma pregunta y la respuesta simple es:

  • $this requiere una instancia de la clase
  • self:: no lo hace

Siempre que esté utilizando métodos estáticos o atributos estáticos y desee llamarlos sin tener un objeto de la clase instanciado, debe usarlos self:para llamarlos, porque $thissiempre requiere la creación de un objeto.

Miguel
fuente
7

$this se refiere al objeto de clase actual, self refiere a la clase actual (No objeto). La clase es el plano del objeto. Entonces define una clase, pero construye objetos.

En otras palabras, use self for staticythis for none-static members or methods .

también en el escenario hijo / padre self / parentse usa principalmente para identificar miembros y métodos de clase padre e hijo.

Rakesh Singh
fuente
7

Además ya $this::no se ha discutido todavía.

Solo con fines informativos, a partir de PHP 5.3 cuando se trata de objetos instanciados para obtener el valor de alcance actual, en lugar de usar static::, uno puede usar alternativamente $this::así.

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

El uso del código anterior no es una práctica común o recomendada, pero es simplemente para ilustrar su uso, y es actuar más como un "¿Sabía que?" en referencia a la pregunta del póster original.

También representa el uso de, $object::CONSTANTpor ejemplo echo $foo::NAME;, en lugar de$this::NAME;

fyrye
fuente
5

Úselo selfsi desea llamar a un método de una clase sin crear un objeto / instancia de esa clase, ahorrando así RAM (a veces use self para ese propósito). En otras palabras, en realidad está llamando a un método estáticamente. Uso thispara la perspectiva del objeto.

minhajul
fuente
2

Caso 1: El uso selfse puede usar para constantes de clase

 clase claseA { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}

Si desea llamarlo fuera de la clase, use classA::POUNDS_TO_KILOGRAMSpara acceder a las constantes

Caso 2: para propiedades estáticas

clase classC {
     función pública __construct () { 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}
li bing zhao
fuente
1

De acuerdo con php.net hay tres palabras clave especiales en este contexto: self, parenty static. Se utilizan para acceder a propiedades o métodos desde dentro de la definición de clase.

$this, por otro lado, se usa para llamar a una instancia y métodos de cualquier clase siempre que esa clase sea accesible.

Fil
fuente
-1

self ::  palabra clave utilizada para la clase actual y, básicamente, se utiliza para acceder a miembros estáticos, métodos y constantes. Pero en el caso de $ this no puede llamar al miembro estático, método y funciones.

Puede usar la palabra clave self :: en otra clase y acceder a los miembros estáticos, el método y las constantes. Cuándo se extenderá desde la clase padre e igual en el caso de $ this palabra clave. Puede acceder a los miembros no estáticos, el método y la función en otra clase cuando se extenderá desde la clase principal.

El código que figura a continuación es un ejemplo de self :: y $ this palabra clave. Simplemente copie y pegue el código en su archivo de código y vea el resultado.

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
fuente