Getting your Trinity Audio player ready... |
Como desenvolvedores PHP, precisamos conhecer muitos recursos da linguagem para tornar nosso código fácil de escrever e manter. Sem ser explicitamente informado sobre uma parte da linguagem, é difícil até mesmo saber que ela existe, então hoje, vamos discutir os métodos mágicos que nossas classes têm e como devemos usá-los para escrever nosso código.
O que são métodos mágicos?
Métodos mágicos são métodos especiais definidos dentro da linguagem principal do PHP que são chamados quando certas ações são executadas em um objeto. Eles nos permitem substituir como o PHP interagiria com o objeto normalmente e injetar nossa própria lógica em seu lugar.
Os métodos mágicos são prefixados com dois sublinhados (__
) e têm uma grande variedade de usos. Todos os métodos mágicos são opcionais, então não sinta que você deve criá-los. Eles estão aqui para tornar nosso trabalho mais fácil e não para criar trabalho extra para nós. Pelo menos não intencionalmente.
construir() e destruir()
Sem dúvida, o método mágico mais importante em PHP é o __construct
método. O __construct()
método é usado para definir como uma classe deve ser construída (ou inicializada). O corpo do __construct
O método inclui coisas como inicializar variáveis e chamar outras funções dentro da classe.
class User
{
public int $id;
public function __construct(public string $name)
{
$this->id = rand(1, 9999);
}
}
$testUser = new User("Scott Keck-Warren");
echo $testUser->id;
Ao contrário de outras linguagens de programação, o PHP permite apenas um único construtor. Portanto, se você precisar de várias maneiras de inicializar uma classe, precisará passar por alguns obstáculos, fornecendo uma lógica interna que determina o que fazer com base nos tipos de parâmetros ou usar o Padrão de Design do Método de Fábrica, que fornece funções estáticas para fornecer diferentes maneiras de inicializar a classe.
O __destruct
function é usada quando não há referências a um objeto em Sua visita nos ajuda a continuar oferecendo o melhor para você! ou durante a sequência de desligamento do PHP. Isso é útil para limpar recursos como conexões a serviços externos ou ponteiros para arquivos que sua classe pode ter criado durante seu ciclo de vida.
Por exemplo, nesta aula, vamos repetir o nome das funções conforme elas são chamadas e você pode ver a sequência de chamadas de funções.
class StartUpAndShutDown
{
public function __construct()
{
echo "__construct", PHP_EOL;
}
public function __destruct()
{
echo "__destruct", PHP_EOL;
}
public function doSomething(): void
{
echo "doSomething", PHP_EOL;
}
}
$testClass = new StartUpAndShutDown();
$testClass->doSomething();
unset($testClass);
A saída disso é:
__construct
doSomething
__destruct
chamar() e chamarStatic()
As próximas duas funções que discutiremos são: __call
e __callStatic
funções. Elas são chamadas pelo PHP quando tentamos chamar uma função ou função estática que não existe, então, em vez de emitir um erro fatal, podemos interceptar a chamada e executar algum tipo de ação em seu lugar.
class ClassWithCallAndStaticCall
{
public function __call(string $name, array $arguments): mixed
{
echo PHP_EOL, PHP_EOL;
echo $name, " ", var_export($arguments);
return null;
}
public static function __callStatic(string $name, array $arguments): mixed
{
echo PHP_EOL, PHP_EOL;
echo $name, " ", var_export($arguments);
return null;
}
}
$testClass = new ClassWithCallAndStaticCall();
$testClass->oldFunctionName();
ClassWithCallAndStaticCall::mispelledFunction();
O $name
argumento é o nome do método que está sendo chamado e o $arguments
argument é uma matriz contendo os parâmetros passados para a função que estamos tentando chamar.
Existem vários casos de uso para isso, mas o que eu sempre gosto de usar é para poder escrever funções que permitem que você passe um parâmetro como parte do nome da função. Dessa forma, podemos escrever uma chamada de função como whereName("Scott")
e que seja equivalente a where("name", "Scott")
é uma pequena diferença que torna o código um pouco mais fácil de ler.
class ClassWithCallAndStaticCall
{
public function __call(string $name, array $arguments): mixed
{
if ($name == "whereName") {
$this->where("name", $arguments[0]);
return $this;
}
return $this;
}
public function where(string $key, string $value): void
{
var_dump("where {$key} = {$value}");
}
}
$testClass = new ClassWithCallAndStaticCall();
$testClass->whereName("Scott");
O outro caso de uso para isso é ser capaz de remapear dinamicamente uma chamada de função. Por exemplo, podemos estar renomeando uma função (uma das melhores ferramentas de refatoração que temos em nossa caixa de ferramentas) e precisamos manter o nome da função antiga, mas queremos mantê-la “oculta” do novo desenvolvimento. Podemos fazer isso usando o __call()
e __callStatic
função.
class OurClass
{
public function __call(string $name, array $arguments): mixed
{
if ($name == "oldName") {
$this->newName($arguments[0]);
return $this;
}
return $this;
}
public function newName(string $value): void
{
var_dump("newName with {$value}");
}
}
$testClass = new OurClass();
$testClass->oldName("Scott");
A grande desvantagem de usar __call
e __callStatic
é que nossos editores (e quaisquer ferramentas de análise de código estático como PHPStan) não saberão sobre eles. Para contornar isso, podemos definir a função como parte do docBlock no início da definição da classe.
class OurClass {
}
pegar(), definir(), isset(), e não definido()
Este próximo lote de métodos mágicos fornece lógica para suportar propriedades inacessíveis ou inexistentes. pegar(), Os métodos mágicos set() são usados ao ler ou escrever, respectivamente, em uma propriedade inacessível ou inexistente. O método mágico isset() é usado ao chamar isset()
ou empty()
em uma propriedade inacessível ou inexistente. O métodos mágicos unset() são chamados durante a execução unset()
em uma propriedade inacessível ou inexistente.
Há alguns casos de uso para isso, mas há dois dos quais gosto mais.
O primeiro é fornecer uma maneira de fazer com que uma classe rastreie todos os seus dados dentro de um array em vez de propriedades. Isso é útil se estivermos carregando um número desconhecido de propriedades (talvez de um banco de dados) e precisarmos mantê-las em um formato que possamos manipular facilmente e, então, enviá-las de volta para uma camada de persistência ou serviço externo.
class DynamicFields
{
public array $properties = [];
public function __set(string $name, mixed $value): void
{
$this->properties[$name] = $value;
}
Sua visita nos ajuda a continuar oferecendo o melhor para você! public function __get(string $name): mixed
{
return $this->properties[$name];
}
public function __isset(string $name): bool
{
return isset($this->properties[$name]);
}
public function __unset(string $name): void
{
unset($this->properties[$name]);
}
}
$dynamicField = new DynamicFields();
$dynamicField->name = "Scott";
echo $dynamicField->name, PHP_EOL;
echo isset($dynamicField->name) ? "Yes" : "No", PHP_EOL;
unset($dynamicField->name);
echo isset($dynamicField->name) ? "Yes" : "No", PHP_EOL;
Isso produzirá:
Scott
Yes
No
A outra é renomear uma propriedade e fornecer acesso ao nome antigo enquanto você (ou outros) atualizam o código deles.
class DeprecatedName
{
public string $email = "[email protected]";
public function __set(string $name, mixed $value): void
{
if ($name == "emailAddress") {
$this->email = $value;
}
}
public function __get(string $name): mixed
{
if ($name == "emailAddress") {
return $this->email;
}
}
}
$deprecatedName = new DeprecatedName();
$deprecatedName->emailAddress = "[email protected]";
echo $deprecatedName->email, PHP_EOL;
Novamente, a grande desvantagem dessas funções é que nossos editores e ferramentas de análise de código estático não saberão sobre as propriedades. Para contornar isso, podemos definir as propriedades como parte do docBlock no início da definição da classe.
serializar() e deinicializar()
O serializar() e métodos mágicos unserialize() são usados pelo PHP quando serializamos ou desserializamos uma instância da nossa classe para determinar quais propriedades devem ser incluídas e como queremos codificar os dados. Fizemos um vídeo inteiro sobre serialização em PHP e você deveria conferir [()].
Como exemplo, temos uma classe de usuário abaixo.
class User
{
public string $password = "";
public function __construct(
public string $name,
public string $email
) {
$this->password = "originalPassword";
}
public function __serialize(): array
{
return [
"name" => $this->name,
"email" => $this->email,
];
}
public function __unserialize(array $data): void
{
$this->name = $data["name"];
$this->email = $data["email"];
$this->password = "Monkey1234!";
}
}
$user = new User("Scott", "[email protected]");
echo $user->name, PHP_EOL;
echo $user->password, PHP_EOL;
$serilized = serialize($user);
$redone = unserialize($serilized);
echo $redone->name, PHP_EOL;
echo $redone->password, PHP_EOL;
Podemos chamar o serialize()
função em uma instância da classe e obter uma string que representa a classe. Normalmente, o PHP pegaria todas as propriedades e colocaria na string. Neste caso, definimos um __serialize
método na classe que é chamado para definir quais propriedades serão exportadas.
Então podemos chamar o unserialize()
função na string e recriar a classe como ela existia. Neste caso, definimos a __unserialize()
método na classe que é chamado em vez disso com uma matriz associativa contendo os valores.
Isso gerará a seguinte saída:
Scott
originalPassword
Scott
Monkey1234!
Há também um __set_state()
método mágico é chamado muito parecido com o __unserialize
função, mas é usada para recriar uma classe exportada usando o var_export()
função. Não vou demonstrar como funciona porque é muito difícil argumentar por que a maioria das pessoas precisaria disso quando há opções melhores. Se eu estiver errado, me avise na seção de comentários.
__paraString()
O __toString
O método mágico é usado se tentarmos converter uma instância da nossa classe em uma string.
Isso é útil se você quiser ser capaz de gerar facilmente sua classe em um formato legível. Às vezes, incluo isso em classes às quais preciso aplicar alguma formatação, como uma classe de usuário onde rastreamos o primeiro e o último nome separadamente. Podemos então usar o __toString
método para concatená-los automaticamente quando exibimos o usuário.
class StringableUser
{
public function __construct(private string $first, private string $last) { }
public function __toString(): string
{
return "{$this->first} {$this->last}";
}
}
$stringableUser = new StringableUser("Scott", "Keck-Warren");
echo $stringableUser, PHP_EOL;
__invocar()
O __invoke()
O método mágico é usado para nos permitir chamar um objeto como uma função. Isso é útil se você precisa passar um Callable
argumento para uma função e precisa de uma maneira de organizar o chamável para uso posterior (em vez de escrever um fechamento idêntico em vários locais).
Por exemplo, se tivermos o seguinte código:
function displayInformation(Callable $func) {
echo "Calling Callable", PHP_EOL;
$func();
}
class Scott {
public function __invoke() {
echo "Keck-Warren";
}
}
$callableClass = new Scott();
echo displayInformation($callableClass);
Isto exibirá:
Calling Callable
Keck-Warren
__clone()
O __clone()
O método magic é chamado logo após uma instância de uma classe ter sido clonada. Isso é útil se você precisa atualizar uma propriedade ou fazer uma cópia profunda do objeto.
Como exemplo, na classe abaixo estamos mantendo o controle de quando a classe foi criada. Quando clonamos a classe, precisamos atualizar a propriedade criada com um novo DateTimeImmutable [()] o que podemos fazer facilmente no __clone()
método.
class CloneableClass
{
public \DateTimeImmutable $created;
public function __construct()
{
$this->created = new \DateTimeImmutable();
}
public function __clone()
{
$this->created = new \DateTimeImmutable();
}
}
$original = new CloneableClass();
echo $original->created->format("Y-m-d H:i:s"), PHP_EOL;
sleep(4);
$cloned = clone $original;
echo $cloned->created->format("Y-m-d H:i:s"), PHP_EOL;
__debugInfo()
O __debugInfo()
método mágico, que irritantemente é o único método mágico camelCase, é chamado pelo var_dump()
função para obter as propriedades que devem ser mostradas.
class User
{
private string $id = "neverShowThis";
public function __construct(public string $email, private string $password) { }
public function __debugInfo()
{
return [
"email" => $this->email,
"password" => "it's a secret",
];
}
}
$testUser = new User("[email protected]", "mySecurePassword");
var_dump($testUser);
O resultado disto é:
object(User)#1 (2) {
["email"]=>
string(17) "[email protected]"
["password"]=>
string(13) "it's a secret"
}
O que você precisa saber
- Métodos mágicos são métodos que podemos definir em nossas classes
- Interrompa a lógica padrão do PHP
- Muitas opções e casos de uso diferentes
Não perca a chance de explorar nossos produtos na loja.
Dê um passo à frente e Sua visita nos ajuda a continuar oferecendo o melhor para você! sua liberdade financeira trabalhando no conforto da sua casa ou escritório.