Obteniendo el primer carácter de una cadena con $ str [0]

276

Quiero obtener la primera letra de una cadena y he notado que $str[0]funciona muy bien. Simplemente no estoy seguro de si esta es una 'buena práctica', ya que esa notación generalmente se usa con matrices. Esta característica no parece estar muy bien documentada, así que me dirijo a ustedes para que me digan si está bien, en todos los aspectos, ¿usar esta notación?

¿O debería seguir con lo bueno substr($str, 0, 1)?

Además, noté que las llaves ( $str{0}) también funcionan. ¿Que pasa con eso?

Tatu Ulmanen
fuente
55
más 1 para el "buen ol 'substr ($ str, 0, 1)".
Santiago termina SO

Respuestas:

390

Si. Las cadenas se pueden ver como matrices de caracteres, y la forma de acceder a una posición de una matriz es usar el []operador. Por lo general, no hay ningún problema en el uso $str[0](y estoy bastante seguro de que es mucho más rápido que el substr()método).

Solo hay una advertencia con ambos métodos: obtendrán el primer byte , en lugar del primer carácter . Esto es importante si está utilizando codificaciones multibyte (como UTF-8). Si quieres apoyar eso, úsalo mb_substr(). Podría decirse que siempre debe asumir la entrada multibyte en estos días, por lo que esta es la mejor opción, pero será un poco más lenta.

Corvejón
fuente
77
¿PHP $ str [0] tiene en cuenta que puede haber caracteres de 2 bytes de longitud? UTF y tal? (¡aunque substr () tampoco ayuda con eso!)
Tomer W
77
Si desea ser súper seguro, debe mb_substr($str, 0, 1, 'utf-8')hacerlo para no truncar una cadena multibyte.
Vic
18
Aunque esto es más corto y es más fácil de recordar que substr($str, 0, 1), esto confunde a quién lee el código.
trante
10
La elección entre corchetes y substr () es en gran medida una cuestión de preferencia, pero tenga en cuenta que el resultado es diferente cuando se aplica a una cadena vacía. Si $ s = "" entonces $ s [] === "", pero substr ($ s, 0, 1) === falso.
xtempore
9
Si $ s = "", entonces $ s [0] generará un "Aviso: desplazamiento de cadena no inicializado: 0", mientras que substr ($ s, 0, 1) no lo hará.
Chris
46

La sintaxis {} está en desuso a partir de PHP 5.3.0. Se recomiendan corchetes.

Michael Morton
fuente
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
44
@VolkerK: en el enlace que proporcionó, noté que eliminaron la nota en el manual de PHP que dejaron solo: Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose.así que me pregunto si decidieron que el uso {}ya no está en desuso a partir de PHP 6
Marco Demaio
1
@MarcoDemaio El enlace ahora dice lo que dice MichaelMorton.
Tino
1
"no da ninguna indicación de desaprobación" - De hecho, el mensaje de desaprobación se eliminó en la revisión 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
A partir de hoy (10 de mayo de 18), una cita de los documentos PHP que le gustaron : Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose. Parece que esta sintaxis se mantendrá por un tiempo.
Fr0zenFyr
25

Digamos que solo quieres el primer carácter de una parte de $ _POST, llamémoslo 'tipo'. Y ese $ _POST ['tipo'] es actualmente 'Control'. Si en este caso si lo usa $_POST['type'][0], o substr($_POST['type'], 0, 1)volverá C.

Sin embargo, si el cliente tuviera que modificar los datos que le envían, a partir typede type[], por ejemplo, y, a continuación, enviar 'Control' y 'prueba' como los datos para esta matriz, $_POST['type'][0]ahora volverá Controlen lugar de Cque, substr($_POST['type'], 0, 1)simplemente acaba de fallar.

Entonces, sí, puede haber un problema con el uso $str[0], pero eso depende de las circunstancias circundantes.

gattsbr
fuente
2
Como nota al margen para eludir este problema en particular y en cualquier caso, uno siempre debe realizar la validación de datos. if (true === is_string($_POST['type']))
fyrye
13

Mi única duda sería cuán aplicable sería esta técnica en cadenas de varios bytes, pero si eso no es una consideración, entonces sospecho que está cubierto. (En caso de duda, mb_substr()parece una opción obviamente segura).

Sin embargo, desde una perspectiva general, tengo que preguntarme con qué frecuencia necesita acceder al carácter 'n' en una cadena para que esto sea una consideración clave.

John Parker
fuente
9

Varía según los recursos, pero puede ejecutar el script a continuación y verlo usted mismo;)

<?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;
?>

Algunos números de referencia (en una vieja máquina CoreDuo)

$ 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 usar los operadores []o {}es más o menos lo mismo.

Willy Stadnick
fuente
2
Buena prueba! Algunos números de un Xeon de 3 años: el microtiempo de flotación promedio usando "array []" es 2.2427082061768E-7 el microtime de flotador promedio usando "substr ()" es 3.9647579193115E-7 el microtime de flotación promedio usando "array {}" es 2.1522283554077E-7
Ellert van Koperen
para mediciones precisas, es mejor que haga microtiempo fuera del ciclo, y no mezcle los diferentes enfoques dentro del mismo ciclo.
PypeBros
1
no mezclar la ejecución de testAy testBdentro de los mismos bucles significa que usted es capaz de detectar, por ejemplo, el hecho de que testBes un asesino de testAcaché mientras que es compatible con caché. Cuando ambos están en el mismo bucle, se mide que tienen los mismos tiempos porque testBel testAalmacenamiento en caché está contaminado .
PypeBros
1
Del mismo modo, evitaría generar cadenas o randoms dentro de los bucles de prueba y tenerlos listos en una matriz cercana.
PypeBros
1
-1; dejando de lado el mecanismo de temporización cuestionable (sería mejor cronometrar muchas operaciones que cronometrarlas una a la vez; me preocupaba al leer esto que solo el tiempo dedicado a hacer la microtime()llamada supondría la mayor parte de la diferencia horaria, aunque experimentalmente eso parece para no ser cierto), no hay razón para preocuparse por la pequeña diferencia de velocidad aquí. Es una fracción de una millonésima de segundo; cuando se presente alguna vez va a importar?
Mark Amery
6

Hablando como un simple mortal, me quedaría con $str[0]. En lo que a mí respecta, es más rápido comprender el significado de $str[0]un vistazo que substr($str, 0, 1). Esto probablemente se reduce a una cuestión de preferencia.

En cuanto al rendimiento, bueno, perfil perfil perfil. :) O podrías mirar el código fuente de PHP ...

Stephen
fuente
6
$str = 'abcdef';
echo $str[0];                 // a
Jakir Hossain
fuente
66
-1; la pregunta del OP fue si esta sintaxis fue una mala práctica, y usted respondió ... ¿repitiendo la sintaxis, sin ningún comentario? Esta no es una respuesta.
Mark Amery
5

En el caso de cadenas multibyte (unicode), el uso str[0]puede causar problemas. mb_substr()Es una mejor solución. Por ejemplo:

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

Algunos detalles aquí: Obtenga el primer carácter de la cadena UTF-8

Sergey Burish
fuente
¡Gracias por esta solución! si el primer carácter es unicode, [] no funcionará
SunB
1

También he usado esa notación antes, sin efectos secundarios negativos y sin malentendidos. Tiene sentido: una cadena es solo una serie de caracteres, después de todo.

Kaleb Brasee
fuente
No, una cadena no es una matriz de caracteres (al menos como PHP usa esos dos términos). -1.
Mark Amery
@gattsbr internamente lo son, pero en lo que respecta al modelo que expone PHP, son fundamentalmente diferentes. Acceder a un desplazamiento utilizando la notación de corchetes es prácticamente la única operación que tienen en común con las matrices; las funciones de cadena no funcionan en matrices, ni viceversa, y la sintaxis de anexar matriz ( $arr[] = $new_element) no funciona en cadenas. Como tal, no creo que sea útil concebir cadenas como matrices de caracteres.
Mark Amery
@markamery es mejor reescribir el manual de php.net que incluir un tecnicismo tan minúsculo.
gattsbr