Quando usar o self acima de $ this?


Respostas:


1728

Resposta curta

Use $thispara se referir ao objeto atual. Use selfpara se referir à classe atual. Em outras palavras, use $this->memberpara membros não estáticos, use self::$memberpara membros estáticos.

Resposta Completa

Aqui está um exemplo do uso correto de $thise selfpara variáveis ​​de membro não estáticas e 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();
?>

Aqui está um exemplo de uso incorreto de $thise selfpara variáveis ​​de membro não estáticas e 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();
?>

Aqui está um exemplo de polimorfismo com $thisfunções-membro:

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

Aqui está um exemplo de suprimir o comportamento polimórfico usando selfpara funções de membro:

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

A idéia é que $this->foo()chama a foo()função de membro de qualquer que seja o tipo exato do objeto atual. Se o objeto é de type X, chama assim X::foo(). Se o objeto é de type Y, ele chama Y::foo(). Mas com self :: foo (), X::foo()é sempre chamado.

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

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


330
Esta resposta é excessivamente simplista. Conforme apontado em outras respostas, selfé usado com o operador de resolução do escopo ::para se referir à classe atual; isso pode ser feito em contextos estáticos e não estáticos. Além disso, é perfeitamente legal usar $thispara chamar métodos estáticos (mas não para referenciar campos).
Artefacto

50
Considere também o uso de static :: em vez de :: self se você estiver no 5.3+. Pode causar dores de cabeça incontáveis, caso contrário, veja minha resposta abaixo para saber o porquê.
Sqoo

25
-1. Esta resposta é enganosa, leia as outras respostas para obter mais informações.
Pacerier 13/07/2013

6
Pode ser muito simplificado, mas respondeu à minha pergunta de nível básico sem fazer minha cabeça explodir. Eu recebi mais algumas informações que achei úteis mais adiante, mas por enquanto estava apenas tentando descobrir por que atingi meus atributos de classe com $ this-> attrib e as constantes de classe com self :: constant. Isso me ajudou a entender melhor
MydKnight

Que tal $this::?
James

742

A palavra-chave self NÃO se refere apenas à 'classe atual', pelo menos não de uma maneira que restrinja você a membros estáticos. Dentro do contexto de um membro não estático, selftambém fornece uma maneira de ignorar a vtable ( consulte o wiki na vtable ) para o objeto atual. Assim como você pode usar parent::methodName()para chamar a versão dos pais de uma função, também pode chamar self::methodName()para chamar a implementação de classes atual de um 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();

Isso produzirá:

Olá, eu sou Ludwig, o nerd.
Adeus, de Ludwig, a pessoa.

sayHello()usa o $thisponteiro, para que a vtable seja chamada para chamar Geek::getTitle(). sayGoodbye()usa self::getTitle(), portanto, o vtable não é usado e Person::getTitle()é chamado. Nos dois casos, estamos lidando com o método de um objeto instanciado e temos acesso ao $thisponteiro nas funções chamadas.


3
Essa resposta seria ainda melhor se você começasse com uma regra geral e não com uma exceção. É uma questão de estilo, não de conhecimento técnico. Este é o melhor exemplo que eu já vi da diferença entre self :: e $ this->, mas é uma pena esconder isso ao refutar uma noção primeiro.
adjwilli

3
@adjwilli: Por que esse estilo é ruim? Não desperta a consciência se a expectativa (tese) do OP é primeiro desaprovada (antítese) e, em seguida, a explicação é dada como síntese?
21714 ha hakre

1
Acho "classe atual" realmente problemático. Como essa combinação de palavras pode ser entendida como "a classe onde selfestá localizado" / "a definição de classe, é uma parte literal de" e também "a classe do objeto" (o que realmente seria static).
Jakumi

Que tal $this::?
James

1
@ James - não há boas razões para usar $this::; todos os casos possíveis já estão cobertos pelas sintaxes mais usadas. Dependendo do que você quer dizer, o uso $this->, self::ou static::.
Home

461

NÃO USE self::, usestatic::

Há outro aspecto do eu: que vale a pena mencionar. Irritantemente self::se refere ao escopo no ponto de definição e não no ponto de execução . Considere esta classe simples com dois métodos:

class Person
{

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

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

}

Se chamarmos Person::status(), veremos "A pessoa está viva". Agora considere o que acontece quando criamos uma classe que herda disso:

class Deceased extends Person
{

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

}

Ao ligar Deceased::status(), esperamos ver "A pessoa faleceu", no entanto, o que vemos é "A pessoa está viva", pois o escopo contém a definição do método original ao chamarself::getStatus() foi definida.

O PHP 5.3 tem uma solução. o static::operador de resolução implementa "ligação estática tardia", que é uma maneira elegante de dizer que está vinculada ao escopo da classe chamada. Mude a linha status()para static::getStatus() e os resultados são o que você esperaria. Nas versões mais antigas do PHP, você terá que encontrar um kludge para fazer isso.

Veja a documentação do PHP

Então, para responder à pergunta não como solicitado ...

$this->refere-se ao objeto atual (uma instância de uma classe), enquanto static::refere-se a uma classe


6
E as constantes de classe?
Kevin Bond

53
"Chamando Falecido :: status (), esperamos ver" Pessoa falecida "". Não. Esta é uma chamada de função estática, portanto não há polimorfismo envolvido.
Cquezel

2
De todas as falhas do PHP, eu acho que isso não é loucura. De que outra forma eles permitiriam que os codificadores designassem métodos na classe atual (em vez de procurá-los na vtable)? Se o tivessem nomeado de maneira diferente (talvez com sublinhados de destaque), as pessoas que desejam esse recurso o criticariam por ser feio. Senão, seja qual for o nome sensato que eles usem, parece que sempre haveria pessoas facilmente confusas que o criticariam por ser um comportamento "insano", provavelmente alheio à forma como o envio de métodos funciona.
tne

2
O exemplo parece confuso para mim: eu vejo o getStatusmétodo como um que eu chamaria de instância de classe, não de classe.
Jānis Elmeris 17/07/2015

1
@ SQL - dizendo "NÃO USE self ::, use static ::" é um argumento estranho a ser feito - essas deliberadamente não são a mesma operação. Eu acho que o que você está realmente dizendo é "fica mais claro se você usa o nome real da classe 'MyClass ::', em vez de 'self ::' . Ou seja, se você deseja o comportamento de self::, pode obtê-lo, menos confusamente, usando o nome específico da classe, por exemplo MyClass::.
ToolmakerSteve

248

Para realmente entender o que estamos falando quando falamos sobre selfversus $this, precisamos realmente descobrir o que está acontecendo nos níveis conceitual e prático. Eu realmente não sinto que nenhuma das respostas faça isso adequadamente, então aqui está minha tentativa.

Vamos começar falando sobre o que classe e um objeto .

Classes e objetos, conceitualmente

Então, o que é uma aula ? Muitas pessoas o definem como um modelo ou modelo para um objeto. De fato, você pode ler mais sobre classes no PHP aqui . E até certo ponto é isso que realmente é. Vejamos uma classe:

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

Como você pode ver, existe uma propriedade nessa classe chamada $namee um método (função) chamado sayHello().

É muito importante observar que a classe é uma estrutura estática. O que significa que a classe Person, uma vez definida, é sempre a mesma em todos os lugares.

Um objeto, por outro lado, é chamado de instância de uma classe. O que isso significa é que pegamos o "blueprint" da classe e o usamos para fazer uma cópia dinâmica. Agora, esta cópia está vinculada especificamente à variável em que está armazenada. Portanto, qualquer alteração em uma instância é local para ela.

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

Criamos novas instâncias de uma classe usando o newoperador

Portanto, dizemos que uma classe é uma estrutura global e um objeto é uma estrutura local. Não se preocupe com essa ->sintaxe engraçada , vamos abordar isso daqui a pouco.

Outra coisa sobre a qual devemos falar é que podemos verificar se uma instância é uma instanceofclasse específica: $bob instanceof Personque retorna um booleano se a $bobinstância foi criada usando a Personclasse ou um filho de Person.

Estado definidor

Então, vamos nos aprofundar no que uma classe realmente contém. Existem 5 tipos de "coisas" que uma classe contém:

  1. Propriedades - Pense nelas como variáveis ​​que cada instância conterá.

    class Foo {
        public $bar = 1;
    }
  2. Propriedades estáticas - pense nelas como variáveis ​​compartilhadas no nível da classe. Significando que eles nunca são copiados por cada instância.

    class Foo {
        public static $bar = 1;
    }
  3. Métodos - São funções que cada instância conterá (e operará em instâncias).

    class Foo {
        public function bar() {}
    }
  4. Métodos estáticos - são funções compartilhadas por toda a classe. Eles não operam em instâncias, mas apenas nas propriedades estáticas.

    class Foo {
        public static function bar() {}
    }
  5. Constantes - constantes resolvidas em classe. Não indo mais fundo aqui, mas adicionando a integridade:

    class Foo {
        const BAR = 1;
    }

Então, basicamente, estamos armazenando informações no contêiner de classe e objeto usando "dicas" sobre estática que identificam se a informação é compartilhada (e, portanto, estática) ou não (e, portanto, dinâmica).

Estado e Métodos

Dentro de um método, a instância de um objeto é representada pela $thisvariável O estado atual desse objeto está lá e a mutação (alteração) de qualquer propriedade resultará em uma alteração nessa instância (mas não em outras).

Se um método é chamado estaticamente, a $thisvariável não está definida . Isso ocorre porque não há instância associada a uma chamada estática.

O interessante aqui é como as chamadas estáticas são feitas. Então, vamos falar sobre como acessamos o estado:

Estado de acesso

Então agora que armazenamos esse estado, precisamos acessá-lo. Isso pode ser um pouco complicado (ou muito mais que um pouco), então vamos dividir isso em dois pontos de vista: de fora de uma instância / classe (digamos, de uma chamada de função normal ou do escopo global) e dentro de uma instância / class (de dentro de um método no objeto).

De fora de uma instância / classe

Do lado de fora de uma instância / classe, nossas regras são bastante simples e previsíveis. Temos dois operadores e cada um nos diz imediatamente se estamos lidando com uma instância ou uma classe estática:

  • ->- operador de objeto - sempre é usado quando estamos acessando uma instância.

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

    É importante observar que a chamada Person->foonão faz sentido (já que Personé uma classe, não uma instância). Portanto, esse é um erro de análise.

  • ::- scope-resolution-operator - Isso sempre é usado para acessar uma propriedade ou método estático de classe.

    echo Foo::bar()

    Além disso, podemos chamar um método estático em um objeto da mesma maneira:

    echo $foo::bar()

    É extremamente importante observar que, quando fazemos isso de fora , a instância do objeto fica oculta do bar()método. Significando que é exatamente o mesmo que em execução:

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

Portanto, $thisnão está definido na chamada estática.

De dentro de uma instância / classe

As coisas mudam um pouco aqui. Os mesmos operadores são usados, mas seu significado se torna significativamente desfocado.

O operador de objeto -> ainda é usado para fazer chamadas para o estado da instância do objeto.

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

Chamar o bar()método $foo(uma instância de Foo) usando o operador de objeto: $foo->bar()resultará na versão da instância de $a.

Então é assim que esperamos.

O significado do ::operador muda. Depende do contexto da chamada para a função atual:

  • Dentro de um contexto estático

    Dentro de um contexto estático, todas as chamadas feitas usando ::também serão estáticas. Vejamos um exemplo:

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

    A chamada Foo::bar()chamará o baz()método estaticamente e, portanto $this, não será preenchida. Vale a pena notar que nas versões recentes do PHP (5.3+) isso acionará um E_STRICTerro, porque estamos chamando métodos não estáticos estaticamente.

  • Dentro de um contexto de instância

    Em um contexto de instância, por outro lado, as chamadas feitas usando ::dependem do receptor da chamada (o método que estamos chamando). Se o método for definido como static, ele usará uma chamada estática. Caso contrário, ele encaminhará as informações da instância.

    Portanto, observando o código acima, a chamada $foo->bar()retornará true, pois a chamada "estática" acontece dentro de um contexto de instância.

Faz sentido? Não achava isso. É confuso.

Palavras-chave de atalho

Como amarrar tudo junto usando nomes de classe é bastante sujo, o PHP fornece três palavras-chave básicas de "atalho" para facilitar a resolução do escopo.

  • self- Refere-se ao nome da classe atual. O self::baz()mesmo acontece Foo::baz()com a Fooclasse (qualquer método nela).

  • parent - Refere-se ao pai da classe atual.

  • static- Refere-se à classe chamada. Graças à herança, as classes filho podem substituir métodos e propriedades estáticas. Portanto, chamá-los usando o staticnome de uma classe em vez de um nome de classe nos permite resolver de onde a chamada veio, em vez do nível atual.

Exemplos

A maneira mais fácil de entender isso é começar a examinar alguns exemplos. Vamos escolher uma aula:

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

Agora, também estamos olhando para herança aqui. Ignore por um momento que este é um modelo de objeto ruim, mas vamos ver o que acontece quando brincamos com isso:

$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

Portanto, o contador de ID é compartilhado entre as instâncias e os filhos (porque estamos usando selfpara acessá-lo. Se o usássemos static, poderíamos substituí-lo em uma classe filho).

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

Observe que estamos sempre executando o método da Person::getName() instância . Mas estamos usando o parent::getName()para fazer isso em um dos casos (o caso filho). É isso que torna essa abordagem poderosa.

Palavra de cautela # 1

Observe que o contexto de chamada é o que determina se uma instância é usada. Portanto:

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

Nem sempre é verdade.

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

Agora é realmente estranho aqui. Estamos chamando uma classe diferente, mas a $thisque é passada para o Foo::isFoo()método é a instância de $bar.

Isso pode causar todos os tipos de erros e problemas conceituais com o WTF. Então eu sugiro evitar o ::operador de dentro métodos de instância em qualquer coisa, exceto esses três "atalho" palavras-chave virtuais ( static, self, e parent).

Palavra de cautela # 2

Observe que métodos e propriedades estáticas são compartilhados por todos. Isso os torna basicamente variáveis ​​globais. Com todos os mesmos problemas que vêm com globais. Portanto, eu hesitaria muito em armazenar informações em métodos / propriedades estáticas, a menos que você se sinta à vontade em ser verdadeiramente global.

Palavra de cautela # 3

Em geral, convém usar o que é conhecido como ligação estática tardia usando em staticvez de self. Mas observe que eles não são a mesma coisa; portanto, dizer "sempre use em staticvez de selfé realmente míope. Em vez disso, pare e pense na chamada que deseja fazer e pense se deseja que as classes filho possam substituir a estática resolvida". ligar.

TL / DR

Que pena, volte e leia. Pode ser muito longo, mas é longo, porque esse é um tópico complexo

TL / DR # 2

Ok, tudo bem. Em resumo, selfé usado para referenciar o nome da classe atual dentro de uma classe, onde, como $thisse refere à instância do objeto atual . Observe que selfé um atalho de copiar / colar. Você pode substituí-lo com segurança pelo nome da sua classe e funcionará bem. Mas $thisé uma variável dinâmica que não pode ser determinada com antecedência (e pode até não ser sua classe).

TL / DR # 3

Se o operador de objeto for usado ( ->), você sempre saberá que está lidando com uma instância. Se o operador de resolução de escopo for usado ( ::), você precisará de mais informações sobre o contexto (já estamos em um contexto de objeto? Estamos fora de um objeto? Etc).


1
Palavra de cautela # 1: $ this não será definido ao chamar um método estático: 3v4l.org/9kr0e
Mark Achee

Bem ... $thisnão será definido se você seguir "Padrões Estritos" e não chamar métodos estaticamente que não sejam definidos como estáticos. Vejo o resultado que você explicou aqui: 3v4l.org/WeHVM Concordou, muito estranho.
Mark Achee

2
Depois de ler a descrição longa por completo, senti-me com preguiça de rolar acima novamente para votá-la. Brincadeira, eu votei na votação: D. Obrigado, isso é muito útil.
Mr_Green 04/10

3
seria bom adicionar uma explicação clara sobre a diferença entre self :: $ property e self :: property; Eu acho que isso é bastante confuso demais
Tommaso Barbugli

1
O WoC # 1 se comporta de maneira diferente desde o PHP 7. Como Foo::isFoo()é chamado estaticamente, $thisnão será definido. Esse é um comportamento mais intuitivo na minha opinião. - Outro resultado diferente é dado se Barfor estendido de Foo. Então a chamada Foo::isFoo()estaria realmente dentro do contexto da instância (não específico do PHP7).
22916 Kontrollfreak

117

self(não $ self) refere-se ao tipo de classe, em que como $thisrefere-se à instância atual da classe. selfé para uso em funções de membro estático para permitir o acesso a variáveis ​​de membro estático. $thisé usado em funções-membro não estáticas e é uma referência à instância da classe na qual a função-membro foi chamada.

Porque thisé um objeto, você o usa como:$this->member

Como selfnão é um objeto, é basicamente um tipo que se refere automaticamente à classe atual, você o usa como:self::member


97

$this-> é usado para se referir a uma instância específica de variáveis ​​de uma classe (variáveis ​​de membro) ou métodos.

Example: 
$derek = new Person();

$ derek agora é uma instância específica de Person. Toda pessoa tem um nome e sobrenome, mas $ derek tem nome e sobrenome específicos (Derek Martin). Dentro da instância $ derek, podemos nos referir a esses como $ this-> first_name e $ this-> last_name

ClassName :: é usado para se referir a esse tipo de classe e suas variáveis ​​estáticas, métodos estáticos. Se ajudar, você pode substituir mentalmente a palavra "estático" por "compartilhado". Por serem compartilhados, não podem se referir a $ this, que se refere a uma instância específica (não compartilhada). Variáveis ​​estáticas (ou seja, estática $ db_connection) podem ser compartilhadas entre todas as instâncias de um tipo de objeto. Por exemplo, todos os objetos de banco de dados compartilham uma única conexão (conexão estática $).

Exemplo de variáveis ​​estáticas: finja que temos uma classe de banco de dados com uma variável de membro único: static $ num_connections; Agora, coloque isso no construtor:

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

Assim como os objetos têm construtores, eles também têm destruidores, que são executados quando o objeto morre ou é desativado:

function __destruct()
{
    $num_connections--;
}

Toda vez que criamos uma nova instância, ela aumenta nosso contador de conexões em um. Sempre que destruirmos ou pararmos de usar uma instância, ele diminuirá o contador de conexões em um. Dessa maneira, podemos monitorar o número de instâncias do objeto de banco de dados que usamos:

echo DB::num_connections;

Como $ num_connections é estático (compartilhado), ele refletirá o número total de objetos de banco de dados ativos. Você pode ter visto essa técnica usada para compartilhar conexões de banco de dados entre todas as instâncias de uma classe de banco de dados. Isso é feito porque a criação da conexão com o banco de dados leva muito tempo, portanto, é melhor criar apenas uma e compartilhá-la (isso é chamado de Padrão Singleton).

Métodos estáticos (por exemplo, public static View :: format_phone_number ($ digits)) podem ser usados ​​SEM primeiro instanciar um desses objetos (ou seja, eles não se referem internamente a $ this).

Exemplo 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 você pode ver, a função estática pública prettyName não sabe nada sobre o objeto. É apenas trabalhar com os parâmetros que você passa, como uma função normal que não faz parte de um objeto. Por que se preocupar, então, se pudéssemos tê-lo como parte do objeto?

  1. Primeiro, anexar funções a objetos ajuda a manter as coisas organizadas, para que você saiba onde encontrá-las.
  2. Segundo, evita conflitos de nomes. Em um grande projeto, é provável que dois desenvolvedores criem funções getName (). Se um cria um ClassName1 :: getName () e o outro cria ClassName2 :: getName (), não há problema algum. Sem conflito. Yay métodos estáticos!

SELF :: Se você estiver codificando fora do objeto que possui o método estático ao qual deseja se referir, deverá chamá-lo usando o nome do objeto View :: format_phone_number ($ phone_number); Se você está codificando dentro do objeto que possui o método estático que você deseja consultar, você pode tanto usar o nome View :: format_phone_number do objeto ($ pn), ou você pode usar o self :: format_phone_number ($ pn) atalho

O mesmo vale para variáveis ​​estáticas: Exemplo: View :: templates_path versus self :: templates_path

Dentro da classe DB, se estivéssemos nos referindo a um método estático de outro objeto, usaríamos o nome do objeto: Exemplo: Session :: getUsersOnline ();

Mas se a classe DB quisesse se referir a sua própria variável estática, ela apenas diria self: Exemplo: self :: connection;

Espero que ajude a esclarecer as coisas :)


Ótima resposta. Eu só quero salientar que, ao se referir a um atributo estático, você precisa usar um $sinal. Por exemploself::$templates_path
henrywright

30

A partir deste post :

  • self refere-se à classe atual
  • self pode ser usado para chamar funções estáticas e referenciar variáveis ​​de membro estáticas
  • self pode ser usado dentro de funções estáticas
  • self também pode desativar o comportamento polimórfico ignorando a tabela
  • $this refere-se ao objeto atual
  • $this pode ser usado para chamar funções estáticas
  • $thisnão deve ser usado para chamar variáveis ​​de membro estáticas. Use em selfvez disso.
  • $this não pode ser usado dentro de funções estáticas

26

No PHP, você usa a palavra-chave self para acessar propriedades e métodos estáticos.

O problema é que você pode substituir $this->method()por self::method()qualquer lugar, independentemente de method()ser declarado estático ou não. Então, qual deles você deve usar?

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

Neste exemplo, self::who()sempre produzirá 'pai', enquanto $this->who()dependerá de qual classe o objeto possui.

Agora podemos ver que self refere-se à classe na qual é chamado, enquanto $thisrefere-se à classe do objeto atual .

Portanto, você deve usar o self somente quando $thisnão estiver disponível ou quando não desejar permitir que as classes descendentes substituam o método atual.


22

Dentro de uma definição de classe, $thisrefere-se ao objeto atual, enquanto selfrefere-se à classe atual.

É necessário fazer referência a um elemento de classe usando selfe a um elemento de objeto usando $this.

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

21

Aqui está um exemplo do uso correto de $ this e self para variáveis ​​de membro não estáticas e 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();
?> 

21

De acordo com http://www.php.net/manual/en/language.oop5.static.php, não existe $self. Existe apenas $this, para se referir à instância atual da classe (o objeto), e self, que pode ser usado para se referir a membros estáticos de uma classe. A diferença entre uma instância de objeto e uma classe entra em jogo aqui.


9
Sugestão: Leia esta resposta ao tropeçar em ácido.
a20

16

Creio que a questão não era se você pode chamar o membro estático da classe ligando ClassName::staticMember. A questão era qual a diferença entre usar self::classmembere $this->classmember.

Por exemplo, os dois exemplos a seguir funcionam sem erros, independentemente de você usar self::ou nã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;
    }
}

É especialmente engraçado que você comece sua resposta com "Eu acredito que a pergunta não era se você poderia chamar o membro estático da classe chamando ClassName :: staticMember. A pergunta era qual a diferença entre usar self :: classmember e $ this-> classmember" e então você não mostra nenhuma diferença. De fato, você mostra uma instância em que as duas opções funcionam de forma idêntica. -1
Buttle Butkus

No entanto, útil. O escopo era sobre resolução e esta parte não está clara no manual php. Continuo a achar diferentes tratamentos
renoirb

2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun

16

self refere-se à classe atual (na qual é chamada),

$thisrefere-se ao objeto atual. Você pode usar estática em vez de si mesma. Veja o exemplo:

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

Saída: filho pai


16
  • O ponteiro do objeto $thispara refere-se ao objeto atual.
  • O valor da classe staticrefere-se ao objeto atual.
  • O valor da classe selfrefere-se à classe exata em que foi definida.
  • O valor da classe parentrefere-se ao pai da classe exata em que foi definido.

Veja o exemplo a seguir, que mostra 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"

Na maioria das vezes você deseja consultar a classe atual e é por isso que você usa staticou $this. No entanto, há momentos em que você precisa, self porque deseja a classe original, independentemente do que a estender. (Muito, muito raramente)


14

Como ninguém aqui falou sobre performances, aqui está uma pequena referência que eu fiz (5.6):

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

Esses são os resultados para 2 000 000 execuções, e aqui está o código que eu usei:

<?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
Chamar a função sem operação 2 000 000 vezes dura 1s. Tenho que amar o PHP.
precisa saber é

Bom e velho PHP. :) Mas uma chamada = 0.001ms. Isso e ruim?
tleb

Acredito que isso (e coisas semelhantes) é por que coisas como ORMs ficam lentas, a menos que você armazene em cache coisas, e geradores de sites estáticos são uma coisa.
9/09/09

2
É teoricamente deveria ter processador de 1 ciclo de clock, o que faz ao redor 1 / 2e9 s = 0.5 nsnos dias de hoje
amigos

Apenas releia minha resposta. Cuidado: ele cria a classe também. Não sei por que não usei a usepalavra - chave tbh, mas não tenho mais o PHP para refazer uma referência e não sinto vontade de reinstalá-la.
tleb

13

Quando selfé usado com o ::operador, refere-se à classe atual, que pode ser feita em contextos estáticos e não estáticos. $thisrefere-se ao próprio objeto. Além disso, é perfeitamente legal usar $thispara chamar métodos estáticos (mas não para se referir a campos).


8

Encontrei a mesma pergunta e a resposta simples é:

  • $this requer uma instância da classe
  • self:: não

Sempre que você estiver usando métodos estáticos ou atributos estáticos e quiser chamá-los sem ter um objeto da classe instanciado, precisará usá self:-los para chamá-los, porque $thissempre exige que o objeto seja criado.


7

$thisrefere-se ao objeto de classe atual, selfrefere-se à classe atual (Não objeto). A classe é o blueprint do objeto. Então você define uma classe, mas constrói objetos.

Então, em outras palavras, use self for staticethis for none-static members or methods .

também no cenário filho / pai self / parenté usado principalmente para identificar membros e métodos da classe pai e filho.


7

Além disso, uma vez que $this::ainda não foi discutido.

Apenas para fins informativos, a partir do PHP 5.3, quando se lida com objetos instanciados para obter o valor atual do escopo, em vez de usar static::, pode-se usar $this::como alternativa .

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

O uso do código acima não é uma prática comum ou recomendada, mas apenas para ilustrar seu uso e é mais como um "Você sabia?" em referência à pergunta do pôster original.

Também representa o uso de, $object::CONSTANTpor exemplo, echo $foo::NAME;em oposição a$this::NAME;


5

Use selfse você quiser chamar o método de uma classe sem criar um objeto / instância dessa classe, economizando RAM (às vezes, use-se para esse fim). Em outras palavras, na verdade, ele está chamando um método estaticamente. Use thispara perspectiva de objeto.


2

Caso 1: uso self pode ser usado para constantes de classe

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

Se você quiser chamá-lo fora da classe, use classA::POUNDS_TO_KILOGRAMSpara acessar as constantes

Caso 2: Para propriedades estáticas

classe classC {
     função pública __construct () { 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}

1

De acordo com php.net há três palavras-chave especiais neste contexto: self, parente static. Eles são usados ​​para acessar propriedades ou métodos de dentro da definição de classe.

$this, por outro lado, é usado para chamar uma instância e métodos de qualquer classe, desde que essa classe esteja acessível.


-1

self ::  palavra-chave usada para a classe atual e basicamente é usada para acessar membros, métodos e constantes estáticos. Mas no caso de $ this, você não pode chamar o membro estático, método e funções.

Você pode usar a palavra-chave self :: em outra classe e acessar os membros, método e constantes estáticos. Quando será estendido da classe pai e o mesmo no caso de $ this keyword. Você pode acessar os membros não estáticos, método e função em outra classe quando ela for estendida da classe pai.

O código fornecido abaixo é um exemplo de self :: e $ this keyword. Basta copiar e colar o código no seu arquivo de código e ver a saída.

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());
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.