Obtendo o primeiro caractere de uma string com $ str [0]

276

Quero receber a primeira letra de uma string e notei que $str[0]funciona muito bem. Só não tenho certeza se isso é 'boa prática', pois essa notação é geralmente usada com matrizes. Esse recurso não parece estar muito bem documentado, por isso estou recorrendo a vocês para me dizer se está tudo bem - em todos os aspectos - usar essa notação?

Ou devo apenas me ater ao bom e velho substr($str, 0, 1)?

Além disso, observei que chaves ( $str{0}) também funcionam. O que há com isso?

Tatu Ulmanen
fonte
5
mais 1 para o "bom e velho substr" ($ str, 0, 1) ".
Santiago encerra SO

Respostas:

390

Sim. As strings podem ser vistas como matrizes de caracteres, e a maneira de acessar uma posição de uma matriz é usar o []operador. Normalmente, não há nenhum problema em usar $str[0](e tenho certeza que é muito mais rápido que o substr()método).

Há apenas uma ressalva nos dois métodos: eles obterão o primeiro byte , e não o primeiro caractere . Isso é importante se você estiver usando codificações multibyte (como UTF-8). Se você deseja apoiar isso, use mb_substr(). Indiscutivelmente, você deve sempre assumir a entrada multibyte hoje em dia, portanto essa é a melhor opção, mas será um pouco mais lenta.

Jarrete
fonte
7
O PHP $ str [0] leva em consideração que pode haver caracteres de 2Byte long? UTF e tal? (mesmo que substr () não ajudar com isso também!)
Tomer W
77
Se você deseja ser super super seguro, você deve segui- mb_substr($str, 0, 1, 'utf-8')lo para não truncar uma sequência de vários bytes.
Vic
18
Embora isso seja mais curto e mais fácil de lembrar substr($str, 0, 1), isso confunde quem lê o código.
trante
10
A escolha entre colchetes e substr () é uma questão de preferência, mas lembre-se de que o resultado é diferente quando aplicado a uma sequência vazia. Se $ s = "" então $ s [] === "", mas substr ($ s, 0, 1) === false.
Xtempore
9
Se $ s = "", então $ s [0] gerará um "Aviso: deslocamento de cadeia não inicializado: 0", enquanto substr ($ s, 0, 1) não.
Chris28 /
46

A sintaxe {} está obsoleta no PHP 5.3.0. Os colchetes são recomendados.

Michael Morton
fonte
14
docs.php.net/language.types.string :Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose. However, this syntax is deprecated as of PHP 5.3.0. Use square brackets instead, such as $str[42].
VolkerK
4
@ VolkerK: no link que você forneceu, notei que eles removeram a nota no manual do PHP que eles deixaram apenas: Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose.Então, eu estou pensando se eles decidiram que o uso {}NÃO é mais descontinuado a partir do PHP 6
Marco Demaio
1
@MarcoDemaio O link agora mostra o que MichaelMorton diz.
Tino
1
"não dá indicação de descontinuação" - Na verdade, a mensagem de descontinuação foi removida na revisão 304518 - The curly-brackets-string-index-accessor-syntax does not emit any deprecation notice, although the original notice have been on and off for PHP 5.x, it does not in the current version, thrus we should not label it as deprecated. Related to bug #52254- svn.php.net/repository/phpdoc/en/trunk/language/types/…
VolkerK 15/03/17
A partir de hoje (10 de maio de 18), uma citação dos documentos PHP amados : Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose. Parece que essa sintaxe vai ficar por um tempo.
Fr0zenFyr
25

Digamos que você queira apenas o primeiro caracter de uma parte de $ _POST, vamos chamá-lo de 'type'. E esse $ _POST ['type'] atualmente é 'Control'. Se, neste caso, se você usar $_POST['type'][0], ou substr($_POST['type'], 0, 1)você Cvoltará.

No entanto, se o lado do cliente foram para modificar os dados que você enviar, a partir typede type[], por exemplo, e em seguida, enviar 'Control' e 'Test' como os dados para esta matriz, $_POST['type'][0]vai agora regressar Controlao invés de Cao passo substr($_POST['type'], 0, 1)vai simplesmente falhar.

Então, sim, pode haver um problema com o uso $str[0], mas isso depende da circunstância circundante.

gattsbr
fonte
2
Como uma nota lateral para contornar esse problema específico, em qualquer um dos casos, deve-se sempre executar a validação dos dados. if (true === is_string($_POST['type']))
precisa saber é o seguinte
13

Minha única dúvida seria a aplicabilidade dessa técnica em cadeias de bytes múltiplos, mas se isso não for considerado, suspeito que você esteja coberto. (Em caso de dúvida, mb_substr()parece uma escolha obviamente segura.)

No entanto, de uma perspectiva geral, tenho que me perguntar quantas vezes você precisa acessar o caractere n-ésimo em uma string para que isso seja uma consideração importante.

John Parker
fonte
9

Isso varia dependendo dos recursos, mas você pode executar o script abaixo e ver por si mesmo;)

<?php
$tests = 100000;

for ($i = 0; $i < $tests; $i++)
{
    $string = md5(rand());
    $position = rand(0, 31);

    $start1 = microtime(true);
    $char1 = $string[$position];
    $end1 = microtime(true);
    $time1[$i] = $end1 - $start1;

    $start2 = microtime(true);
    $char2 = substr($string, $position, 1);
    $end2 = microtime(true);
    $time2[$i] = $end2 - $start2;

    $start3 = microtime(true);
    $char3 = $string{$position};
    $end3 = microtime(true);
    $time3[$i] = $end3 - $start3;
}

$avg1 = array_sum($time1) / $tests;
echo 'the average float microtime using "array[]" is '. $avg1 . PHP_EOL;

$avg2 = array_sum($time2) / $tests;
echo 'the average float microtime using "substr()" is '. $avg2 . PHP_EOL;

$avg3 = array_sum($time3) / $tests;
echo 'the average float microtime using "array{}" is '. $avg3 . PHP_EOL;
?>

Alguns números de referência (em uma máquina CoreDuo antiga)

$ php 1.php 
the average float microtime using "array[]" is 1.914701461792E-6
the average float microtime using "substr()" is 2.2536706924438E-6
the average float microtime using "array{}" is 1.821768283844E-6

$ php 1.php 
the average float microtime using "array[]" is 1.7251944541931E-6
the average float microtime using "substr()" is 2.0931363105774E-6
the average float microtime using "array{}" is 1.7225742340088E-6

$ php 1.php 
the average float microtime using "array[]" is 1.7293763160706E-6
the average float microtime using "substr()" is 2.1037721633911E-6
the average float microtime using "array{}" is 1.7249774932861E-6

Parece que o uso dos operadores []ou {}é mais ou menos o mesmo.

Willy Stadnick
fonte
2
Bom teste! Alguns números de um Xeon de 3 anos: o tempo médio de flutuação usando "array []" é 2.2427082061768E-7 o tempo médio de flutuação usando "substr ()" é 3.9647579193115E-7 o tempo médio de flutuação usando "array {}" é 2.1522283554077E-7
Ellert van Koperen
para medições precisas, você deve melhorar o microtime fora do loop e não misturar as diferentes abordagens no mesmo loop.
PypeBros
1
não misturar a execução de testAe testBdentro dos mesmos loops significa que você é capaz de detectar, por exemplo, o fato de que testBum cache-killer testAé compatível com o cache. Quando ambos estão no mesmo loop, são medidos para ter os mesmos tempos porque o cache testBpoluído testA.
PypeBros
1
da mesma forma, eu evitaria gerar strings ou randoms nos loops de teste e os deixaria prontos em uma matriz próxima.
PypeBros
1
-1; deixando de lado o mecanismo de tempo questionável (seria melhor cronometrar muitas operações do que cronometrá-las uma de cada vez; fiquei preocupado em ler isso que apenas o tempo gasto para fazer a microtime()chamada compensaria a maior parte da diferença de tempo, embora experimentalmente isso pareça para não ser verdade), não há razão para se preocupar com a pequena diferença de velocidade aqui. É uma fração de milionésimo de segundo; quando é que isto nunca vai importar?
Mark Amery
6

Falando como um mero mortal, eu continuaria $str[0]. Para mim, é mais rápido entender o significado de $str[0]uma olhada do que substr($str, 0, 1). Isso provavelmente se resume a uma questão de preferência.

Quanto ao desempenho, bem, perfil perfil. :) Ou você pode examinar o código-fonte PHP ...

Stephen
fonte
6
$str = 'abcdef';
echo $str[0];                 // a
Jakir Hossain
fonte
6
-1; a pergunta do OP era se essa sintaxe era uma prática ruim e você respondeu repetindo a sintaxe, sem nenhum comentário? Esta não é uma resposta.
Mark Amery
5

No caso de seqüências multibyte (unicode), o uso str[0]pode causar um problema. mb_substr()é uma solução melhor. Por exemplo:

$first_char = mb_substr($title, 0, 1);

Alguns detalhes aqui: Obtenha o primeiro caractere da string UTF-8

Sergey Burish
fonte
Obrigado por esta solução! Se o primeiro caractere é unicode, [] não vai funcionar
SunB
1

Também já usei essa notação, sem efeitos colaterais ruins e sem mal-entendidos. Faz sentido - afinal, uma string é apenas uma matriz de caracteres.

Kaleb Brasee
fonte
Não, uma string não é uma matriz de caracteres (pelo menos como o PHP usa esses dois termos). -1.
Mark Amery
@gattsbr internamente, mas no que diz respeito ao modelo que o PHP expõe, eles são fundamentalmente diferentes. Acessar um deslocamento usando a notação de colchete é praticamente a única operação que eles têm em comum com matrizes; As funções de string não funcionam em matrizes, nem vica versa, e a sintaxe de adição de matriz ( $arr[] = $new_element) não funciona em strings. Como tal, não acho útil conceber cadeias como matrizes de caracteres.
Mark Amery
É melhor que o @markamery reescreva o manual do php.net e inclua um minúsculo detalhe técnico.
22817 Gattsbr #