Qual é a diferença entre :: (dois pontos duplos) e -> (seta) no PHP?

196

Existem duas maneiras distintas de acessar métodos no PHP, mas qual é a diferença?

$response->setParameter('foo', 'bar');

e

sfConfig::set('foo', 'bar');

Estou assumindo que ->(traço com sinal maior que ou chevron) é usado para funções para variáveis ​​e ::(dois pontos duplos) é usado para funções para classes. Corrigir?

O =>operador de atribuição é usado apenas para atribuir dados em uma matriz? Isso contrasta com o =operador de atribuição usado para instanciar ou modificar uma variável?

Joe
fonte
1
Possível duplicata da diferença entre dois pontos e operadores de seta no PHP?
Organic Advocate

Respostas:

172

Quando a parte esquerda é uma instância de objeto, você usa ->. Caso contrário, você usa ::.

Isso significa que ->é usado principalmente para acessar membros da instância (embora também possa ser usado para acessar membros estáticos, esse uso é desencorajado), enquanto ::geralmente é usado para acessar membros estáticos (embora, em alguns casos especiais, seja usado para acessar membros da instância )

Em geral, ::é usado para a resolução do âmbito , e que podem ter um nome de classe, parent, self, ou (em PHP 5.3) staticpara o seu lado esquerdo. parentrefere-se ao escopo da superclasse da classe em que é usada; selfrefere-se ao escopo da classe em que é usada; staticrefere-se ao "chamado escopo" (consulte ligações estáticas tardias ).

A regra é que uma chamada com ::é uma chamada de instância se e somente se:

  • o método de destino não é declarado como estático e
  • existe um contexto de objeto compatível no momento da chamada, o que significa que eles devem ser verdadeiros:
    1. a chamada é feita a partir de um contexto em que $thisexiste e
    2. a classe de $thisé a classe do método que está sendo chamado ou uma subclasse dele.

Exemplo:

class A {
    public function func_instance() {
        echo "in ", __METHOD__, "\n";
    }
    public function callDynamic() {
        echo "in ", __METHOD__, "\n";
        B::dyn();
    }

}

class B extends A {
    public static $prop_static = 'B::$prop_static value';
    public $prop_instance = 'B::$prop_instance value';

    public function func_instance() {
        echo "in ", __METHOD__, "\n";
        /* this is one exception where :: is required to access an
         * instance member.
         * The super implementation of func_instance is being
         * accessed here */
        parent::func_instance();
        A::func_instance(); //same as the statement above
    }

    public static function func_static() {
        echo "in ", __METHOD__, "\n";
    }

    public function __call($name, $arguments) {
        echo "in dynamic $name (__call)", "\n";
    }

    public static function __callStatic($name, $arguments) {
        echo "in dynamic $name (__callStatic)", "\n";
    }

}

echo 'B::$prop_static: ', B::$prop_static, "\n";
echo 'B::func_static(): ', B::func_static(), "\n";
$a = new A;
$b = new B;
echo '$b->prop_instance: ', $b->prop_instance, "\n";
//not recommended (static method called as instance method):
echo '$b->func_static(): ', $b->func_static(), "\n";

echo '$b->func_instance():', "\n", $b->func_instance(), "\n";

/* This is more tricky
 * in the first case, a static call is made because $this is an
 * instance of A, so B::dyn() is a method of an incompatible class
 */
echo '$a->dyn():', "\n", $a->callDynamic(), "\n";
/* in this case, an instance call is made because $this is an
 * instance of B (despite the fact we are in a method of A), so
 * B::dyn() is a method of a compatible class (namely, it's the
 * same class as the object's)
 */
echo '$b->dyn():', "\n", $b->callDynamic(), "\n";

Resultado:

B :: $ prop_static: B :: $ prop_static value
B :: func_static (): em B :: func_static

$ b-> prop_instance: B :: $ prop_instance value
$ b-> func_static (): em B :: func_static

$ b-> func_instance ():
em B :: func_instance
em A :: func_instance
em A :: func_instance

$ a-> dyn ():
em A :: callDynamic
no dyn dinâmico (__callStatic)

$ b-> dyn ():
em A :: callDynamic
no dyn dinâmico (__call)
Artefacto
fonte
3
" ->é usado principalmente para acessar membros da instância (embora também possa ser usado para acessar membros estáticos, esse uso é desencorajado)" Eu não sabia que poderia ser. Portanto, se ele "funciona" de alguma maneira quando usado para acessar membros estáticos - que diferença de comportamento seria de esperar se o usássemos incorretamente dessa maneira? Apenas por curiosidade.
Lucider
4
@ucideer No caso de métodos estáticos, é uma questão de boas práticas (o método pertence à própria classe), mas o PHP não reclama se chamar um método estático com ->. Obviamente, pode ser necessário instanciar a classe apenas para chamar um método estático, para que também ocorra um impacto no desempenho. Com propriedades, no entanto, há mais problemas. Um aviso estrito é gerado e pode ou não funcionar . Observe que o inverso também é verdadeiro - você pode chamar um método de instância estaticamente, mas isso é ainda pior (e você não pode usar $thisessa implementação de método).
Artefacto
52

::é usado em contexto estático , ie. quando algum método ou propriedade é declarado como estático:

class Math {
    public static function sin($angle) {
        return ...;
    }
}

$result = Math::sin(123);

Além disso, o ::operador (o Operador de resolução de escopo, também conhecido como Paamayim Nekudotayim ) é usado em contexto dinâmico quando você invoca um método / propriedade de uma classe pai:

class Rectangle {
     protected $x, $y;

     public function __construct($x, $y) {
         $this->x = $x;
         $this->y = $y;
     }
}

class Square extends Rectangle {
    public function __construct($x) {
        parent::__construct($x, $x);
    }
}

->é usado em contexto dinâmico , ie. quando você lida com alguma instância de alguma classe:

class Hello {
    public function say() {
       echo 'hello!';
    }
}

$h = new Hello();
$h->say();

A propósito: não acho que usar o Symfony seja uma boa ideia quando você não tem nenhuma experiência em POO.

Crozin
fonte
24

Na verdade, por esse símbolo, podemos chamar um método de classe que é estático e não depende de outra inicialização ...

class Test {

    public $name;

    public function __construct() {
        $this->name = 'Mrinmoy Ghoshal';
    }

    public static function doWrite($name) {
        print 'Hello '.$name;
    }

    public function write() {
        print $this->name;
    }
}

Aqui, a doWrite()função não depende de nenhum outro método ou variável e é um método estático. É por isso que podemos chamar esse método por esse operador sem inicializar o objeto dessa classe.

Test::doWrite('Mrinmoy'); // Output: Hello Mrinmoy.

Mas se você quiser chamar o writemétodo dessa maneira, ele gerará um erro porque depende da inicialização.

Mrinmoy Ghoshal
fonte
15

O =>operador é usado para atribuir pares de valores-chave em uma matriz associativa. Por exemplo:

$fruits = array(
  'Apple'  => 'Red',
  'Banana' => 'Yellow'
);

Seu significado é semelhante na foreachdeclaração:

foreach ($fruits as $fruit => $color)
  echo "$fruit is $color in color.";
Casablanca
fonte
14

A diferença entre métodos e propriedades estáticos e instanciados parece ser um dos maiores obstáculos para aqueles que estão começando com o OOP PHP no PHP 5.

O operador de dois pontos duplos (chamado Paamayim Nekudotayim do hebraico - trivialidades) é usado ao chamar um objeto ou propriedade de um contexto estático . Isso significa que uma instância do objeto ainda não foi criada.

O operador de seta, por outro lado, chama métodos ou propriedades que a partir de uma referência de uma instância do objeto.

Os métodos estáticos podem ser especialmente úteis em modelos de objetos vinculados a um banco de dados para métodos de criação e exclusão, pois você pode definir o valor de retorno para o ID da tabela inserido e, em seguida, usar o construtor para instanciar o objeto pelo ID da linha.

DeaconDesperado
fonte
2

Sim, acabei de acertar o meu primeiro 'PHP Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM'. Meu mal, eu tinha um $instance::method()que deveria ter sido $instance->method(). Parvo eu.

O estranho é que isso ainda funciona muito bem na minha máquina local (executando o PHP 5.3.8) - nada, nem mesmo um aviso com error_reporting = E_ALL - mas não no servidor de teste, apenas explode com um erro de sintaxe e uma tela branca no navegador. Como o registro do PHP foi desativado na máquina de teste e a empresa de hospedagem estava muito ocupada para ativá-lo, não era muito óbvio.

Portanto, aviso: aparentemente, algumas instalações do PHP permitem usar um $ instance :: method (), enquanto outros não.

Se alguém puder expandir o motivo, faça isso.

PapaFreud
fonte