Significado de três pontos (...) em PHP

125

Qual é o significado de Três pontos (...) em PHP?

Enquanto estou instalando o Magento 2 no meu servidor, recebo um erro. Investigue o código e descubra que há um ponto Três (...), que está produzindo o erro. Eu mencionei o código abaixo

return new $type(...array_values($args));
abu abu
fonte
empacotamento / desempacotamento de array introduzido no PHP 5.6
Mark Baker
Você verificou os requisitos antes de instalar: devdocs.magento.com/guides/v2.0/install-gde/…
Mathieu de Lorimier
4
Apenas um comentário aleatório, este é o operador de propagação em JS. :)
Chris Happy
@ChrisHappy neste caso é realmente o operador resto .
Kenny Horna
Veja também: Operador PHP splat
dreftymac

Respostas:

191

O ...$stré chamado de operador splat em PHP .

Este recurso permite que você capture um número variável de argumentos para uma função, combinado com argumentos "normais" passados, se desejar. É mais fácil ver com um exemplo:

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

A lista de parâmetros na declaração da função contém o ...operador e basicamente significa "... e todo o resto deve entrar em $ strings". Você pode passar 2 ou mais argumentos para esta função e o segundo e os subsequentes serão adicionados ao array $ strings, prontos para serem usados.

Espero que isto ajude!

Saumya Rastogi
fonte
1
Obrigado :), por que devo usar o operador SPLAT, em vez disso posso passar todas essas strings em uma matriz como o segundo argumento ???
bikash.bilz
3
@ Bikash.bilz Vou falar pelo respondente: acho que é apenas açúcar sintático . O operador splat evita que você rodeie os argumentos com [e ]. Não é um grande benefício, mas acho que fica bem.
Kodos Johnson
20
Você também pode digitar os parâmetros variáveis. Portanto, no PHP 7.2, você pode definir function myFunc($foo, string ...$bar). Em seguida, $barfornece à sua função um array de strings e nada mais, garantido em tempo de execução. Você não pode fazer isso com um único parâmetro de matriz.
Jason
4
Isso é mais do que apenas um açúcar de sintaxe, pois permite uma matriz em contextos que, de outra forma, exigiriam um número fixo de strings. O uso de um número fixo de strings exige que você refaça seu código-fonte sempre que o número de strings mudar.
dreftymac
2
Um exemplo fácil é uma assinatura de função usada para consultar um banco de dados. function get_data($fname,$lname,$age)terá que mudar se você quiser campos diferentes daqueles três function get_data(...$fields)não precisa mudar, você só precisa especificar os campos que deseja $fields. @heykatieben
dreftymac
21

Cada resposta se refere à mesma postagem do blog, além delas, aqui está a documentação oficial sobre listas de argumentos de comprimento variável :

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

No PHP 5.6 e posterior, as listas de argumentos podem incluir o token ... para denotar que a função aceita um número variável de argumentos. Os argumentos serão passados ​​para a variável fornecida como um array

Parece que operador "splat" não é um nome oficial, mas é fofo!

rap-2-h
fonte
13

Existem DOIS usos para o token de reticências (...) PHP - pense neles como empacotar um array e desempacotar um array. Ambos os propósitos se aplicam a argumentos de função.


Pacote

Ao definir uma função, se você precisar de um número dinâmico de variáveis ​​fornecidas para a função (ou seja, você não sabe quantos argumentos serão fornecidos para aquela função quando chamada no código), use o token de reticências (...) para capturar todos os argumentos restantes fornecidos para essa função em uma matriz que seja acessível dentro do bloco de funções. O número de argumentos dinâmicos capturados por reticências (...) pode ser zero ou mais.

Por exemplo :

// 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

Quando o empacotamento é usado na instanciação da função, reticências (...) captura todos os argumentos restantes , ou seja, você ainda pode ter qualquer número de argumentos iniciais fixos (posicionais):

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

Descompacte

Como alternativa, ao chamar uma função, se os argumentos que você fornece para essa função são combinados anteriormente em uma matriz, use o token de reticências (...) para converter essa matriz em argumentos individuais fornecidos para a função - cada elemento da matriz é atribuído ao respectivo variável de argumento de função nomeada na definição da função.

Por exemplo:

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

A descompactação é particularmente útil ao usar funções de array para manipular arrays ou variáveis.

Por exemplo, descompactando o resultado de 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
Bloody Knuckles
fonte
4
Esta é a melhor resposta. Explicação e exemplos muito claros. Obrigado!!!
Jee
Descompactar é superutilizado para a função OrX do Doctrine
Erdal G.
5

Para usar este recurso, apenas avise ao PHP que ele precisa descompactar o array em variáveis ​​usando o ... operator. Veja aqui para obter mais detalhes, um exemplo simples poderia ser assim:

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

mail("[email protected]", ...$email);
Desenvolvedor-chefe
fonte
4

O que significa que ele decompõe uma matriz associativa em uma lista. Portanto, você não precisa digitar N parâmetros para chamar um método, apenas um. O método If permite um parâmetro decomposto e se os parâmetros são do mesmo tipo.

Para mim, o mais importante sobre o operador splat é que ele pode ajudar a digitar os parâmetros da matriz de dicas:

$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;
        }
    }
} 

ele economiza algum esforço no controle de tipo, especialmente ao trabalhar com coleções enormes ou muito orientado a objetos.

Importante notar é que ...$arraydecompõe uma matriz, independentemente do tipo de seus itens , portanto, você também pode seguir o caminho feio:

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!

Mas, por favor, não faça isso.

Yergo
fonte
Não é tão feio. Como as funções OrX do Doctrine que precisam de uma lista, mas você precisa passar um array (porque você não sabe quantos elementos irá passar). Acho isso melhor do que usar call_user_func_array
Erdal G.
3

Este é o chamado operador "splat". Basicamente, essa coisa se traduz em "qualquer número de argumentos"; introduzido com PHP 5.6

Veja aqui para mais detalhes.

GhostCat
fonte
3

Parece que ninguém mencionou isso, então veio para ficar [Isso também ajudará o Google (e outros SEs) a guiar os desenvolvedores que estão solicitando parâmetros de descanso em PHP ]:

Como indicado aqui, é chamado de Parâmetros de descanso em JS e eu prefiro essa nomenclatura significativa a esse splat!

No PHP, a funcionalidade fornecida por ... args é chamada de funções Variadic que são introduzidas no PHP5.6. A mesma funcionalidade foi usada para ser implementada usando func_get_args().

Para usá-lo corretamente, você deve usar a sintaxe de parâmetros de resto, em qualquer lugar que ajude a reduzir o código clichê .

Behradkhodayar
fonte
1
mais um para ajudar o Google a encontrar o parâmetro Rest no PHP
kapreski
1

Eu gostaria de compartilhar um uso deste operador no framework Magento, onde ele instancia objetos com parâmetros dinâmicos configuráveis ​​(arquivos de configuração XML).

Como podemos ver a createObjectfunção do fragmento de código a seguir, ela recebe uma matriz dos argumentos preparados para a criação do objeto. Em seguida, ele usa o ...operador (três pontos) para passar os valores da matriz como argumentos reais para o construtor da classe.

<?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) {
            ...
        }
    }

    ...

}
hailong
fonte
1

No PHP 7.4, a reticência também é o operador Spread :

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

Fonte: https://wiki.php.net/rfc/spread_operator_for_array

Jawira
fonte