Como resolver “deve ser uma instância de string, string dada” antes do PHP 7?

217

Aqui está o meu código:

function phpwtf(string $s) {
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

O que resulta neste erro:

Erro fatal capturável: o argumento 1 passado para phpwtf () deve ser uma instância de string, string fornecida

É mais do que um pouco orwelliano ver o PHP reconhecer e rejeitar o tipo desejado na mesma respiração. Existem cinco luzes, caramba.

Qual é o equivalente ao tipo de dica para strings no PHP? Consideração de bônus à resposta que explica exatamente o que está acontecendo aqui.

leepowers
fonte
5
Bem, isso é porque você está fazendo errado. Seu código não deve funcionar, para começar. Leia sobre malabarismo de tipos nos documentos do PHP. O PHP é de tipo dinâmico e de tipo fraco. Você pode usar (string) para converter um argumento em string (apenas no corpo da função), mas só pode sugerir objetos e matrizes como no seu snippet de código.
Richard Knop
7
O problema é que você cometeu um pequeno erro. Há quatro luzes!
CJ Dennis
@Gordon, eu testei no 5.6. Ainda sem sorte.
Pacerier 03/04
@Pacerier Por favor, siga wiki.php.net/rfc para os últimos desenvolvimentos.
Gordon
3
Aparentemente, as dicas de tipo escalar (como o OP intuitivamente esperava ser uma coisa acima) foram finalmente aprovadas sob uma RFC para PHP * 7 *, de acordo com a fonte . Aparentemente, a RFC aprovada também fornece açúcar sintático para valores de retorno de verificação de tipo , bem como parâmetros (argumentos). Faz muito tempo que vem.
SeldomNeedy 28/10

Respostas:

204

Antes do PHP 7, as dicas de tipo só podem ser usadas para forçar os tipos de objetos e matrizes. Tipos escalares não podem ser digitados. Nesse caso, stringé esperado um objeto da classe , mas você está atribuindo um (escalar) string. A mensagem de erro pode ser engraçada, mas não deve funcionar para começar. Dado o sistema de digitação dinâmico, isso realmente faz algum tipo de sentido pervertido.

Você pode apenas "digitar dica" manualmente tipos escalares:

function foo($string) {
    if (!is_string($string)) {
        trigger_error('No, you fool!');
        return;
    }
    ...
}
deceze
fonte
1
@ deceze, existe uma sintaxe para dicas de tipo reverso? Por exemplo, qualquer coisa, exceto matrizes.
Pacerier 03/04
@ Pacerier Não, não há.
deceze
4
Esta resposta não é válida para PHP 7
Jose Nobile
24

No manual do PHP :

As dicas de tipo podem ser apenas do tipo objeto e matriz (desde o PHP 5.1). Sugestões de tipo tradicional com int e string não são suportadas.

Então você tem. A mensagem de erro não é realmente útil, mas eu lhe dou isso.

** Edição 2017 **

O PHP7 introduziu mais declarações de tipo de dados de função, e o link mencionado acima foi movido para Argumentos de função: declarações de tipo . A partir dessa página:

Tipos válidos

  • Nome da classe / interface : o parâmetro deve ser uma instância do nome da classe ou da interface fornecida. (desde o PHP 5.0.0)
  • self : o parâmetro deve ser uma instância da mesma classe em que o método está definido. Isso pode ser usado apenas em métodos de classe e instância. (desde o PHP 5.0.0)
  • matriz : o parâmetro deve ser uma matriz. (desde PHP 5.1.0) callable O parâmetro deve ser válido callable. PHP 5.4.0
  • bool : O parâmetro deve ser um valor booleano. (desde PHP 7.0.0)
  • float : O parâmetro deve ser um número de ponto flutuante. (desde PHP 7.0.0)
  • int : o parâmetro deve ser um número inteiro. (desde PHP 7.0.0)
  • string : O parâmetro deve ser uma string. (desde PHP 7.0.0)
  • iterável : O parâmetro deve ser uma matriz ou uma instância de Traversable. (desde o PHP 7.1.0)

Aviso

Aliases para os tipos escalares acima não são suportados. Em vez disso, eles são tratados como nomes de classe ou interface. Por exemplo, o uso de booleano como parâmetro ou tipo de retorno exigirá um argumento ou valor de retorno que seja uma instância da classe ou da interface booleana, em vez do tipo bool:

<?php
   function test(boolean $param) {}
   test(true);
 ?>

O exemplo acima apresentará:

 Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1

O último aviso é realmente significativo para entender o erro "O argumento deve ser do tipo string, string fornecida"; Como na maioria dos casos, somente nomes de classe / interface são permitidos como tipo de argumento, o PHP tenta localizar o nome de uma classe "string", mas não consegue encontrar nenhum porque é um tipo primitivo, portanto falha com esse erro estranho.

Yanick Rochon
fonte
8

O PHP permite "dicas" onde você fornece uma classe para especificar um objeto. De acordo com o manual do PHP, "As dicas de tipo podem ser apenas do tipo objeto e matriz (desde o PHP 5.1). Dicas de tipo tradicional com int e string não são suportadas." O erro é confuso devido à sua escolha de "string" - coloque "myClass" em seu lugar e o erro será diferente: "O argumento 1 passado para phpwtf () deve ser uma instância de myClass, com a string fornecida"

Sonhos surreais
fonte
3

Como outros já disseram, a dica de tipo atualmente funciona apenas para tipos de objetos. Mas acho que o erro específico que você acionou pode estar na preparação do próximo tipo de string SplString .

Em teoria, ele se comporta como uma string, mas como é um objeto passaria na verificação do tipo de objeto. Infelizmente ainda não está no PHP 5.3, pode vir na 5.4, portanto não testei isso.

mario
fonte
2

A partir do PHP 7,0 declarações de tipo permitir tipos escalares, de forma que estes tipos estão agora disponíveis: self, array, callable, bool, float, int, string. Os três primeiros estavam disponíveis no PHP 5, mas os quatro últimos são novos no PHP 7. Se você usar qualquer outra coisa (por exemplo, integerou boolean) que será interpretada como um nome de classe.

Veja o manual do PHP para mais informações .

TwoStraws
fonte
0

Talvez não seja seguro e bonito, mas se você precisar:

class string
{
    private $Text;
    public function __construct($value)
    {
        $this->Text = $value;
    }

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

function Test123(string $s)
{
    echo $s;
}

Test123(new string("Testing"));
Patrick
fonte
5
Eu ainda poderia criar umnew string(array(1,2,3))
Jimmy T.
0

Eu recebi esse erro ao invocar uma função de um Laravel Controller para um arquivo PHP.

Depois de algumas horas, encontrei o problema: estava usando $ this de dentro de uma função estática.

ecairol
fonte
Using $this when not in object contexté de fato uma mensagem enigmática.
precisa
0

(originalmente publicado por leepowers em sua pergunta)

A mensagem de erro é confusa por um grande motivo:

Nomes de tipos primitivos não são reservados no PHP

A seguir estão todas as declarações de classe válidas:

class string { }
class int { }
class float { }
class double { }

Meu erro foi pensar que a mensagem de erro se referia apenas ao tipo primitivo de string - a palavra "instância" deveria ter me dado uma pausa. Um exemplo para ilustrar mais:

class string { }
$n = 1234;
$s1 = (string)$n;
$s2 = new string();
$a = array('no', 'yes');
printf("\$s1 - primitive string? %s - string instance? %s\n",
        $a[is_string($s1)], $a[is_a($s1, 'string')]);
printf("\$s2 - primitive string? %s - string instance? %s\n",
        $a[is_string($s2)], $a[is_a($s2, 'string')]);

Resultado:

$ s1 - string primitiva? sim - instância de string? não

$ s2 - string primitiva? instância sem string? sim

No PHP, é possível que stringa seja a stringexceto quando na verdade é a string. Como em qualquer linguagem que usa conversão implícita de tipos, o contexto é tudo.

user719662
fonte
-1

Eu acho que typecasting no php no bloco interno, String no PHP não é um objeto como eu sei:

<?php
function phpwtf($s) {
    $s = (string) $s;
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");
subosito
fonte
2
Você pode adicionar a validação is_string () dentro da sua função para impedir que outro valor seja passado para a função.
Sub103 de
1
(string) $spode lançar um erro se $sé um objeto que não pode ser convertido em string (não tem __toString()método implementado), por isso não é tão fácil como isso
Yanick Rochon
Sim Yanick, você está certo. Mas não podemos forçar toda a entrada a ser uma string, certo? é por isso que a exceção vem à tona. Podemos combinar tipo de validações e exceção captura para o resto;)
subosito
Estou apenas dizendo que a conversão de alguma variável em string sem verificar primeiro se a variável pode ser convertida deve ser evitada, principalmente porque capturar exceções é caro e leva a padrões de design ruins / hábitos de codificação.
Yanick Rochon