En PHP 5, ¿cuál es la diferencia entre usar self
y $this
?
¿Cuándo es apropiado cada uno?
En PHP 5, ¿cuál es la diferencia entre usar self
y $this
?
¿Cuándo es apropiado cada uno?
Respuestas:
Use
$this
para referirse al objeto actual. Useself
para referirse a la clase actual. En otras palabras, use$this->member
para miembros no estáticos, useself::$member
para miembros estáticos.
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();
?>
Aquí hay un ejemplo de uso incorrecto 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 self::$non_static_member . ' '
. $this->static_member;
}
}
new X();
?>
Aquí hay un ejemplo de polimorfismo con $this
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 supresión del comportamiento polimórfico mediante el uso self
de 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 lafoo()
función miembro de lo que sea el tipo exacto del objeto actual. Si el objeto es detype X
, así llamaX::foo()
. Si el objeto es detype Y
, llamaY::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
self
se 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 $this
para llamar a métodos estáticos (pero no para hacer referencia a campos).
$this::
?
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, self
tambié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 $this
puntero, 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 $this
puntero dentro de las funciones llamadas.
self
se ubica" / "la definición de clase, es una parte literal de" así como "la clase del objeto" (que en realidad sería static
).
$this::
?
$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::
.
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.
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
getStatus
método como uno que llamaría para una instancia de clase, no para una clase.
self::
, puede obtener eso, menos confusamente, mediante el uso del nombre de clase específico, por ejemplo MyClass::
.
Para comprender realmente de qué estamos hablando cuando hablamos de self
versus $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 .
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 $name
y 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 new
operador.
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 instanceof
clase particular: lo $bob instanceof Person
que devuelve un valor booleano si la $bob
instancia se realizó utilizando la Person
clase o un hijo de Person
.
Así que profundicemos un poco en lo que realmente contiene una clase. Hay 5 tipos de "cosas" que contiene una clase:
Propiedades : piense en ellas como variables que contendrá cada instancia.
class Foo {
public $bar = 1;
}
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;
}
Métodos : son funciones que cada instancia contendrá (y operará en instancias).
class Foo {
public function bar() {}
}
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() {}
}
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).
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 $this
variable 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:
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 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->foo
no tiene sentido (ya que Person
es 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, $this
no está definido en la llamada estática.
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 $this
lo tanto , no se completará. Vale la pena señalar que en versiones recientes de PHP (5.3+) esto provocará un E_STRICT
error, 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.
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 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 métodos y propiedades estáticas. Entonces, llamarlos usando en static
lugar de un nombre de clase nos permite resolver de dónde vino la llamada, en lugar del nivel actual.
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 self
para 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.
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 $this
que 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
, self
y parent
).
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.
En general, querrá usar lo que se conoce como enlace estático tardío utilizando en static
lugar de self
. Pero tenga en cuenta que no son lo mismo, por lo que decir "siempre usar en static
lugar de self
es 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.
Lástima, vuelve y léelo. Puede ser demasiado largo, pero es tan largo porque este es un tema complejo
Está bien. En resumen, self
se utiliza para hacer referencia al nombre de la clase actual dentro de una clase, donde se $this
refiere a la instancia del objeto actual . Tenga en cuenta que self
es un atajo de copiar / pegar. Puede reemplazarlo con seguridad con el nombre de su clase, y funcionará bien. Pero $this
es una variable dinámica que no se puede determinar con anticipación (y puede que ni siquiera sea su clase).
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.).
$this
no 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.
Foo::isFoo()
se llama estáticamente, $this
no se definirá. Ese es un comportamiento más intuitivo en mi opinión. - Se da otro resultado diferente si Bar
se extendiera desde Foo
. Entonces la llamada Foo::isFoo()
estaría realmente dentro del contexto de la instancia (no específica de PHP7).
self
(no $ self) se refiere al tipo de clase, donde se $this
refiere a la instancia actual de la clase. self
se usa en funciones miembro estáticas para permitirle acceder a variables miembro estáticas. $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
Debido a self
que no es un objeto, es básicamente un tipo que se refiere automáticamente a la clase actual, lo usa como:self::member
$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?
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 :)
$
signo. Por ejemploself::$templates_path
self
se refiere a la clase actualself
se puede usar para llamar a funciones estáticas y variables de miembro estáticas de referenciaself
se puede usar dentro de funciones estáticasself
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$this
no debe usarse para llamar a variables miembro estáticas. Usar en suself
lugar.$this
no se puede usar dentro de funciones estáticas
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 $this
refiere a la clase del objeto actual .
Por lo tanto, debe usar self solo cuando $this
no esté disponible o cuando no desee permitir que las clases descendientes sobrescriban el método actual.
Dentro de una definición de clase, se $this
refiere al objeto actual, mientras que se self
refiere 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
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();
?>
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.
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::classmember
y $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;
}
}
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
self
hace referencia a la clase actual (en la que se llama),
$this
se 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
$this
refiere al objeto actual.static
refiere al objeto actual.self
de la clase se refiere a la clase exacta en la que se definió.parent
refiere 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 static
o $this
. Sin embargo, hay momentos en los que necesita self
porque desea la clase original independientemente de lo que la extienda. (Muy, muy raramente)
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();
1 / 2e9 s = 0.5 ns
estos días
use
usé la palabra clave tbh, pero ya no tengo PHP para rehacer un punto de referencia, y realmente no tengo ganas de reinstalarlo.
Me encontré con la misma pregunta y la respuesta simple es:
$this
requiere una instancia de la claseself::
no lo haceSiempre 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 $this
siempre requiere la creación de un objeto.
$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 static
ythis for none-static members or methods
.
también en el escenario hijo / padre self / parent
se usa principalmente para identificar miembros y métodos de clase padre e hijo.
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í.
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::CONSTANT
por ejemplo echo $foo::NAME;
, en lugar de$this::NAME;
Caso 1: El uso self
se 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_KILOGRAMS
para acceder a las constantes
Caso 2: para propiedades estáticas
clase classC { función pública __construct () { self :: $ _ counter ++; $ this-> num = self :: $ _ counter; } }
De acuerdo con php.net hay tres palabras clave especiales en este contexto: self
, parent
y 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.
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());