Znaczenie trzech kropek (…) w PHP

125

Jakie jest znaczenie trzech kropek (...) w PHP?

Podczas instalacji Magento 2 na moim serwerze wystąpił błąd. Zbadaj kod i znajdź trzy kropki (...), które powodują błąd. Wspomniałem o kodzie poniżej

return new $type(...array_values($args));
abu abu
źródło
pakowanie / rozpakowywanie tablic wprowadzone w PHP 5.6
Mark Baker
Czy sprawdziłeś wymagania przed instalacją: devdocs.magento.com/guides/v2.0/install-gde/ ...
Mathieu de Lorimier
4
Tylko przypadkowy komentarz, to jest operator spreadu w JS. :)
Chris Happy
@ChrisHappy w tym przypadku jest to właściwie operator odpoczynku .
Kenny Horna,
Zobacz też: Operator splat PHP
dreftymac

Odpowiedzi:

191

W PHP...$str nazywany jest operatorem splat .

Ta funkcja umożliwia przechwytywanie zmiennej liczby argumentów do funkcji, w połączeniu z „normalnymi” argumentami przekazywanymi, jeśli chcesz. Najłatwiej zobaczyć na przykładzie:

function concatenate($transform, ...$strings) {
    $string = '';
    foreach($strings as $piece) {
        $string .= $piece;
    }
    return($transform($string));
}

echo concatenate("strtoupper", "I'd ", "like ", 4 + 2, " apples");
// This would print:
// I'D LIKE 6 APPLES

Lista parametrów w deklaracji funkcji zawiera ...operator i zasadniczo oznacza "... a wszystko inne powinno trafić do $ string". Możesz przekazać 2 lub więcej argumentów do tej funkcji, a drugi i kolejne zostaną dodane do tablicy $ strings, gotowe do użycia.

Mam nadzieję że to pomoże!

Saumya Rastogi
źródło
1
Dzięki :), dlaczego miałbym używać operatora SPLAT, zamiast tego mogę przekazać wszystkie te ciągi w tablicy jako drugi argument ???
bikash.bilz
3
@ bikash.bilz Porozmawiam w imieniu osoby odpowiadającej: Myślę, że to tylko cukier syntaktyczny . Operator splat chroni cię przed otaczaniem argumentów za pomocą [i ]. Nie jest to duża korzyść, ale myślę, że ładnie wygląda.
Kodos Johnson
20
Możesz także podpowiedzieć parametry wariadyczne. Tak więc w PHP 7.2 możesz zdefiniować function myFunc($foo, string ...$bar). Następnie $bardaje twojej funkcji tablicę ciągów i nic więcej, gwarantowane w czasie wykonywania. Nie możesz tego zrobić z jednym parametrem tablicy.
Jason
4
To coś więcej niż tylko cukier składniowy, ponieważ pozwala na tworzenie tablic w kontekstach, które w innym przypadku wymagałyby określonej liczby ciągów. Korzystanie ze stałej liczby ciągów wymaga ponownego uwzględnienia kodu źródłowego za każdym razem, gdy liczba ciągów może się zmienić.
dreftymac
2
Prostym przykładem jest sygnatura funkcji używana do wysyłania zapytań do bazy danych. function get_data($fname,$lname,$age)będzie musiał się zmienić, jeśli chcesz, aby pola inne niż te trzy function get_data(...$fields)nie musiały się zmieniać, wystarczy określić pola, w których chcesz $fields. @heykatieben
dreftymac
21

Każda odpowiedź odnosi się do tego samego wpisu na blogu, poza nimi znajduje się oficjalna dokumentacja dotycząca list argumentów o zmiennej długości :

http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list

W PHP 5.6 i późniejszych, listy argumentów mogą zawierać token ... oznaczający, że funkcja przyjmuje zmienną liczbę argumentów. Argumenty zostaną przekazane do podanej zmiennej jako tablica

Wygląda na to, że operator "splat" nie jest oficjalną nazwą, ale nadal jest uroczy!

rap-2-godz
źródło
13

Istnieją DWA zastosowania wielokropka (...) token PHP - należy je traktować jako pakowanie tablicy i rozpakowywanie tablicy. Oba cele dotyczą argumentów funkcji.


Pakiet

Podczas definiowania funkcji, jeśli potrzebujesz dynamicznej liczby zmiennych dostarczanych do funkcji (tj. Nie wiesz, ile argumentów zostanie przekazanych do tej funkcji po wywołaniu w kodzie), użyj znacznika wielokropka (...), aby przechwytuje wszystkie pozostałe argumenty dostarczone do tej funkcji do tablicy, która jest dostępna wewnątrz bloku funkcyjnego. Liczba dynamicznych argumentów przechwyconych przez wielokropek (...) może wynosić zero lub więcej.

Na przykład :

// function definition
function sum(...$numbers) { // use ellipsis token when defining function
    $acc = 0;
    foreach ($numbers as $nn) {
        $acc += $nn;
    }
    return $acc;
}

// call the function
echo sum(1, 2, 3, 4); // provide any number of arguments

> 10

// and again...
echo sum(1, 2, 3, 4, 5);

> 15

// and again...
echo sum();

> 0

Gdy podczas tworzenia instancji funkcji używane jest pakowanie, wielokropek (...) przechwytuje wszystkie pozostałe argumenty , tj. Nadal można mieć dowolną liczbę początkowych, ustalonych (pozycyjnych) argumentów:

function sum($first, $second, ...$remaining_numbers) {
    $acc = $first + $second;
    foreach ($remaining_numbers as $nn) {
        $acc += $nn;
    }
    return $acc;
}

// call the function
echo sum(1, 2); // provide at least two arguments

> 3

// and again...
echo sum(1, 2, 3, 4); // first two are assigned to fixed arguments, the rest get "packed"

> 10

Rozpakować

Alternatywnie, podczas wywoływania funkcji, jeśli argumenty, które podajesz do tej funkcji, zostały wcześniej połączone w tablicę, użyj tokenu wielokropka (...), aby przekonwertować tę tablicę na indywidualne argumenty dostarczone do funkcji - każdy element tablicy jest przypisany do odpowiedniego zmienna argumentu funkcji wymieniona w definicji funkcji.

Na przykład:

function add($aa, $bb, $cc) {
    return $aa + $bb + $cc;
}

$arr = [1, 2, 3];
echo add(...$arr); // use ellipsis token when calling function

> 6

$first = 1;
$arr = [2, 3];
echo add($first, ...$arr); // used with positional arguments

> 6

$first = 1;
$arr = [2, 3, 4, 5]; // array can be "oversized"
echo add($first, ...$arr); // remaining elements are ignored

> 6

Rozpakowywanie jest szczególnie przydatne w przypadku używania funkcji tablicowych do manipulowania tablicami lub zmiennymi.

Na przykład rozpakowanie wyniku array_slice :

function echoTwo ($one, $two) {
    echo "$one\n$two";
}

$steaks = array('ribeye', 'kc strip', 't-bone', 'sirloin', 'chuck');

// array_slice returns an array, but ellipsis unpacks it into function arguments
echoTwo(...array_slice($steaks, -2)); // return last two elements in array

> sirloin
> chuck
bloodyKnuckles
źródło
4
To najlepsza odpowiedź. Bardzo jasne wyjaśnienie i przykłady. Dziękuję Ci!!!
Jee
Rozpakowanie jest bardzo przydatne dla funkcji OrX Doctrine
Erdal G.
5

Aby użyć tej funkcji, wystarczy ostrzec PHP, że musi rozpakować tablicę na zmienne przy użyciu rozszerzenia ... operator. Zobacz tutaj, aby uzyskać więcej informacji, prosty przykład mógłby wyglądać następująco:

$email[] = "Hi there";
$email[] = "Thanks for registering, hope you like it";

mail("[email protected]", ...$email);
Główny programista
źródło
4

Oznacza to, że rozkłada tablicę asocjacyjną na listę. Nie musisz więc wpisywać parametrów N, aby wywołać metodę, tylko jedną. Jeśli metoda zezwala na zdekomponowany parametr i jeśli parametry są tego samego typu.

Dla mnie najważniejszą rzeczą dotyczącą operatora splat jest to, że może pomóc w wpisaniu parametrów tablicy podpowiedzi:

$items = [
    new Item(), 
    new Item()
];

$collection = new ItemCollection();
$collection->add(...$items); // !

// what works as well:
// $collection->add(new Item());
// $collection->add(new Item(), new Item(), new Item()); // :(

class Item  {};

class ItemCollection {

    /**
     * @var Item[]
     */
    protected $items = [];

    public function add(Item ...$items)
    {
        foreach ($items as &$item) {
            $this->items[] = $item;
        }
    }
} 

oszczędza trochę wysiłku związanego z kontrolą typów, szczególnie podczas pracy z dużymi kolekcjami lub bardzo zorientowanymi obiektowo.

Ważne jest, aby zauważyć, że należy ...$arraydekomponować tablicę pomimo typu jej elementów , więc możesz również pójść w brzydką drogę:

function test(string $a, int $i) {
    echo sprintf('%s way as well', $a);

    if ($i === 1) {
        echo('!');
    }
}

$params = [
    (string) 'Ugly',
    (int) 1
];

test(...$params);

// Output:
// Ugly way as well!

Ale proszę, nie rób tego.

yergo
źródło
To nie jest takie brzydkie. Podobnie jak w przypadku funkcji OrX Doctrine, które wymagają listy, ale musisz przekazać tablicę (ponieważ nie wiesz, ile elementów przekażesz). Uważam, że jest to lepsze niż używanie call_user_func_array
Erdal G.
3

Jest to tak zwany operator „splat”. Zasadniczo oznacza to „dowolną liczbę argumentów”; wprowadzone w PHP 5.6

Więcej informacji znajdziesz tutaj .

GhostCat
źródło
3

Wygląda na to, że nikt o tym nie wspomniał, więc zostańmy [Pomoże to również Google (i innym SE) poprowadzić twórców, którzy proszą o parametry odpoczynku w PHP ]:

Jak wskazano tutaj, jego nazwa to Rest Parameters w JS i wolę to znaczące nazewnictwo od tego splata!

W PHP funkcjonalność zapewniana przez ... args nazywa się funkcjami wariadycznymi, które zostały wprowadzone w PHP5.6. Ta sama funkcjonalność została zaimplementowana przy użyciu func_get_args().

Aby używać go poprawnie, powinieneś użyć składni parametrów resztowych, wszędzie tam, gdzie pomaga to zredukować standardowy kod .

behradkhodayar
źródło
1
plus jeden za pomoc Google w znalezieniu parametru odpoczynku w PHP
kapreski
1

Chciałbym udostępnić użycie tego operatora we frameworku Magento, gdzie tworzy on instancje obiektów z dynamicznymi parametrami konfigurowalnymi (myślę o plikach konfiguracyjnych XML).

Jak widać, createObjectfunkcja z poniższego fragmentu kodu pobiera tablicę argumentów przygotowaną do stworzenia obiektu. Następnie używa ...operatora (trzy kropki) do przekazania wartości tablicy jako rzeczywistych argumentów do konstruktora klasy.

<?php

namespace Magento\Framework\ObjectManager\Factory;

abstract class AbstractFactory implements \Magento\Framework\ObjectManager\FactoryInterface
{
    ...

    /**
     * Create object
     *
     * @param string $type
     * @param array $args
     *
     * @return object
     * @throws RuntimeException
     */
    protected function createObject($type, $args)
    {
        try {
            return new $type(...array_values($args));
        } catch (\TypeError $exception) {
            ...
        }
    }

    ...

}
witam
źródło
1

W PHP 7.4 wielokropek jest również operatorem Spread :

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];

Źródło: https://wiki.php.net/rfc/spread_operator_for_array

jawira
źródło