magiska metoder

Från Wiki.linux.se
Hoppa till navigering Hoppa till sök

Magiska Metoder (Magic Methods)

Magiska metoder är speciella metoder som åsidosätter PHP:s standardåtgärder när vissa åtgärder utförs på ett objekt.

Varning: Alla metoder som börjar med __ är reserverade av PHP. Därför rekommenderas det inte att använda sådana metodnamn om man inte avser att åsidosätta PHP:s beteende.

Följande metodnamn betraktas som magiska: __construct(), __destruct(), __call(), __callStatic(), ,__get() __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone(), och __debugInfo().

Varning: Alla magiska metoder, med undantag för __construct(), __destruct(), och __clone(), måste deklareras som public, annars genereras en E_WARNING. Före PHP 8.0.0 genererades ingen varning för de magiska metoderna __sleep(), __wakeup(), __serialize(), __unserialize(), och __set_state().

Varning: Om typdeklarationer används i definitionen av en magisk metod måste de vara identiska med den signatur som beskrivs i detta dokument. Annars genereras ett fatalt fel. Före PHP 8.0.0 genererades ingen varning. Dock måste __construct() och __destruct() inte deklarera någon returtyp; annars genereras ett fatalt fel.

__sleep() och __wakeup()

public __sleep(): array
public __wakeup(): void

serialize() kontrollerar om klassen har en funktion med det magiska namnet __sleep(). Om så är fallet utförs den funktionen innan någon serialisering sker. Funktionen kan städa upp objektet och förväntas returnera en array med namnen på alla variabler i det objekt som ska serialiseras. Om metoden inte returnerar något kommer null att serialiseras och en E_NOTICE kommer att genereras.

Notera: Det är inte möjligt för __sleep() att returnera namn på privata egenskaper i föräldrarklasser. Att göra detta resulterar i ett fel på E_NOTICE-nivå. Använd istället __serialize().

Notera: Från och med PHP 8.0.0 genereras en varning om __sleep() returnerar ett värde som inte är en array. Tidigare genererades en notis.

Syftet med __sleep() är att spara eventuell osparad data eller utföra liknande städuppgifter. Funktionen är också användbar om ett mycket stort objekt inte behöver sparas helt.

Å andra sidan kontrollerar unserialize() om det finns en funktion med det magiska namnet __wakeup(). Om den finns kan denna funktion återskapa eventuella resurser som objektet kan ha.

Syftet med __wakeup() är att återställa eventuella databasanslutningar som kan ha förlorats under serialiseringen och utföra andra återinitialiseringar.

Exempel #1 Sömn och uppvaknande

<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;
    
    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }
    
    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }
    
    public function __sleep()
    {
        return array('dsn', 'username', 'password');
    }
    
    public function __wakeup()
    {
        $this->connect();
    }
}
?>

__serialize() och __unserialize()

public __serialize(): array
public __unserialize(array $data): void

serialize() kontrollerar om klassen har en funktion med det magiska namnet __serialize(). Om så är fallet utförs den funktionen innan någon serialisering sker. Funktionen måste konstruera och returnera en associativ array av nyckel/värde-par som representerar objektets serialiserade form. Om ingen array returneras kastas en TypeError.

Notera: Om både __serialize() och __sleep() är definierade i samma objekt kommer endast __serialize() att anropas. __sleep() kommer att ignoreras. Om objektet implementerar Serializable-gränssnittet kommer gränssnittets serialize()-metod att ignoreras och __serialize() användas istället.

Syftet med __serialize() är att definiera en serialiseringsvänlig godtycklig representation av objektet. Elementen i arrayen kan motsvara objektets egenskaper men det är inte ett krav.

Å andra sidan kontrollerar unserialize() om det finns en funktion med det magiska namnet __unserialize(). Om den finns kommer denna funktion att ta emot den återställda arrayen som returnerades från __serialize(). Den kan sedan återställa objektets egenskaper från den arrayen på lämpligt sätt.

Notera: Om både __unserialize() och __wakeup() är definierade i samma objekt kommer endast __unserialize() att anropas. __wakeup() kommer att ignoreras.

Notera: Denna funktionalitet är tillgänglig från och med PHP 7.4.0.

Exempel #2 Serialisering och unserialisering

<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;

    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }

    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }

    public function __serialize(): array
    {
        return [
          'dsn' => $this->dsn,
          'user' => $this->username,
          'pass' => $this->password,
        ];
    }

    public function __unserialize(array $data): void
    {
        $this->dsn = $data['dsn'];
        $this->username = $data['user'];
        $this->password = $data['pass'];

        $this->connect();
    }
}
?>

__toString()

public __toString(): string

Metoden __toString() gör det möjligt för en klass att bestämma hur den kommer att reagera när den behandlas som en sträng. Till exempel vad echo $obj; kommer att skriva ut.

Varning: Från och med PHP 8.0.0 följer returvärdet standard PHP-typssemantik, vilket innebär att det kommer att omvandlas till en sträng om möjligt och om strikt typning är inaktiverad.

Ett Stringable-objekt kommer inte att accepteras av en strängtypsdeklaration om strikt typning är aktiverad. Om ett sådant beteende önskas måste typsdeklarationen acceptera Stringable och string via en unionstyp.

Från och med PHP 8.0.0 kommer alla klasser som innehåller en __toString()-metod också implicit att implementera Stringable-gränssnittet och kommer därmed att klara typtester för det gränssnittet. Det rekommenderas att gränssnittet ändå implementeras explicit.

I PHP 7.4 måste returvärdet vara en sträng, annars kastas ett fel.

Före PHP 7.4.0 måste returvärdet vara en sträng, annars genereras ett fatalt E_RECOVERABLE_ERROR.

Varning: Det var inte möjligt att kasta ett undantag från en __toString()-metod före PHP 7.4.0. Att göra det resulterade i ett fatalt fel.

Exempel #3 Enkelt exempel

<?php
// Deklarera en enkel klass
class TestClass
{
    public $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    public function __toString()
    {
        return $this->foo;
    }
}

$class = new TestClass('Hello');
echo $class;
?>

Det ovanstående exemplet kommer att skriva ut:

Hello

__invoke()

__invoke( ...$values): mixed

Metoden __invoke() anropas när ett skript försöker anropa ett objekt som en funktion.

Exempel #4 Använda __invoke()

<?php
class CallableClass
{
    public function __invoke($x)
    {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>

Det ovanstående exemplet kommer att skriva ut:

int(5) bool(true)

Exempel #5 Använda __invoke()

<?php
class Sort
{
    private $key;

    public function __construct(string $key)
    {
        $this->key = $key;
    }

    public function __invoke(array $a, array $b): int
    {
        return $a[$this->key] <=> $b[$this->key];
    }
}

$customers = [
    ['id' => 1, 'first_name' => 'John', 'last_name' => 'Do'],
    ['id' => 3, 'first_name' => 'Alice', 'last_name' => 'Gustav'],
    ['id' => 2, 'first_name' => 'Bob', 'last_name' => 'Filipe']
];

// sortera kunder efter förnamn
usort($customers, new Sort('first_name'));
print_r($customers);

// sortera kunder efter efternamn
usort($customers, new Sort('last_name'));
print_r($customers);
?>

Det ovanstående exemplet kommer att skriva ut:

Array
(
    [0] => Array
        (
            [id] => 3
            [first_name] => Alice
            [last_name] => Gustav
        )

    [1] => Array
        (
            [id] => 2
            [first_name] => Bob
            [last_name] => Filipe
        )

    [2] => Array
        (
            [id] => 1
            [first_name] => John
            [last_name] => Do
        )

)
Array
(
    [0] => Array
        (
            [id] => 1
            [first_name] => John
            [last_name] => Do
        )

    [1] => Array
        (
            [id] => 2
            [first_name] => Bob
            [last_name] => Filipe
        )

    [2] => Array
        (
            [id] => 3
            [first_name] => Alice
            [last_name] => Gustav
        )

)

__set_state()

static __set_state(array $properties): object

Denna statiska metod anropas för klasser som exporteras av var_export().

Den enda parametern för denna metod är en array som innehåller exporterade egenskaper i form av ['property' => value, ...].

Exempel #6 Använda __set_state()

<?php

class A
{
    public $var1;
    public $var2;

    public static function __set_state($an_array)
    {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

$b = var_export($a, true);
var_dump($b);
eval('$c = ' . $b . ';');
var_dump($c);
?>

Det ovanstående exemplet kommer att skriva ut:

string(60) "A::__set_state(array(
   'var1' => 5,
   'var2' => 'foo',
))"
object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}

Notera: När ett objekt exporteras kontrollerar var_export() inte om __set_state() är implementerat av objektets klass, så att återimportera objekt kommer att resultera i ett Error-undantag om __set_state() inte är implementerat. Detta påverkar särskilt vissa interna klasser. Det är programmerarens ansvar att verifiera att endast objekt som ska återimporteras är sådana vars klass implementerar __set_state().

__debugInfo()

__debugInfo(): array

Denna metod anropas av var_dump() när ett objekt dumpas för att få de egenskaper som ska visas. Om metoden inte är definierad för ett objekt kommer alla publika, skyddade och privata egenskaper att visas.

Exempel #7 Använda __debugInfo()

<?php
class C {
    private $prop;

    public function __construct($val) {
        $this->prop = $val;
    }

    public function __debugInfo() {
        return [
            'propSquared' => $this->prop ** 2,
        ];
    }
}

var_dump(new C(42));
?>

Det ovanstående exemplet kommer att skriva ut:

object(C)#1 (1) {
  ["propSquared"]=>
  int(1764)
}

Sidslut

Orginalhemsidan på Engelska : https://www.php.net/manual/en/language.oop5.magic.php
PHP
Språkreferens
Språkreferens#Klasser_och_Objekt