Obtention du premier caractère d'une chaîne avec $ str [0]

276

Je veux obtenir la première lettre d'une chaîne et j'ai remarqué que cela $str[0]fonctionne très bien. Je ne suis tout simplement pas sûr que ce soit une «bonne pratique», car cette notation est généralement utilisée avec les tableaux. Cette fonctionnalité ne semble pas être très bien documentée, donc je me tourne vers vous pour me dire si c'est correct - à tous égards - d'utiliser cette notation?

Ou devrais-je simplement m'en tenir au bon vieux substr($str, 0, 1)?

J'ai également noté que les accolades ( $str{0}) fonctionnent également. Qu'est-ce qui se passe avec ça?

Tatu Ulmanen
la source
5
plus 1 pour le "bon vieux substrat" ​​($ str, 0, 1) ".
Santiago quitte SO

Réponses:

390

Oui. Les chaînes peuvent être vues comme des tableaux de caractères, et la façon d'accéder à la position d'un tableau est d'utiliser l' []opérateur. Habituellement, il n'y a aucun problème à utiliser $str[0](et je suis sûr que c'est beaucoup plus rapide que la substr()méthode).

Il n'y a qu'une mise en garde avec les deux méthodes: elles obtiendront le premier octet , plutôt que le premier caractère . Ceci est important si vous utilisez des encodages multi-octets (tels que UTF-8). Si vous souhaitez soutenir cela, utilisez mb_substr(). On peut dire que vous devriez toujours supposer une entrée multi-octets de nos jours, c'est donc la meilleure option, mais ce sera légèrement plus lent.

Jarret
la source
7
PHP $ str [0] tient-il compte du fait qu'il peut y avoir des caractères longs de 2 octets? UTF et autres? (même si substr () n'y aide pas non plus!)
Tomer W
77
Si vous voulez être super super sûr, vous devriez y aller mb_substr($str, 0, 1, 'utf-8')pour ne pas tronquer une chaîne multi-octets.
Vic
18
Bien que ce soit plus court et plus facile à retenir que substr($str, 0, 1)cela, cela confond celui qui lit le code.
trante
10
Le choix entre crochets et substr () est en grande partie une question de préférence, mais sachez que le résultat est différent lorsqu'il est appliqué à une chaîne vide. Si $ s = "" alors $ s [] === "", mais substr ($ s, 0, 1) === false.
xtempore
9
Si $ s = "" alors $ s [0] générera un "Remarque: décalage de chaîne non initialisé: 0", contrairement à substr ($ s, 0, 1).
chris
46

La syntaxe {} est obsolète à partir de PHP 5.3.0. Les crochets sont recommandés.

Michael Morton
la source
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: au lien que vous avez fourni, j'ai remarqué qu'ils ont supprimé la note sur le manuel PHP qu'ils ont laissé uniquement: Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose.Je me demande donc s'ils ont décidé que l'utilisation {}n'est plus obsolète à partir de PHP 6
Marco Demaio
1
@MarcoDemaio Le lien indique maintenant ce que dit MichaelMorton.
Tino
1
"ne donne aucune indication de dépréciation" - En effet, le message de dépréciation a été supprimé dans la révision 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
À partir d'aujourd'hui (10 mai 2018), une citation des documents PHP appréciés : Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose. On dirait que cette syntaxe va rester pendant un certain temps.
Fr0zenFyr
25

Disons que vous voulez juste le premier caractère d'une partie de $ _POST, appelons-le 'type'. Et que $ _POST ['type'] est actuellement 'Control'. Si dans ce cas si vous utilisez $_POST['type'][0], ou substr($_POST['type'], 0, 1)vous Creviendrez.

Cependant, si le client devait modifier les données qu'il vous envoie, depuis type à type[]par exemple, puis envoyer «Control» et «Test» en tant que données pour ce tableau, $_POST['type'][0]retournera maintenant Controlplutôt Cquesubstr($_POST['type'], 0, 1) qu'il échouera simplement.

Alors oui, il peut y avoir un problème avec l'utilisation $str[0], mais cela dépend des circonstances environnantes.

gattsbr
la source
2
En guise de remarque pour contourner ce problème particulier et dans les deux cas, il faut toujours effectuer la validation des données. if (true === is_string($_POST['type']))
fyrye
13

Mon seul doute serait de savoir comment cette technique serait applicable sur des chaînes multi-octets, mais si ce n'est pas un facteur, je suppose que vous êtes couvert. (En cas de doute,mb_substr() semble un choix évidemment sûr.)

Cependant, d'un point de vue d'ensemble, je dois me demander à quelle fréquence vous devez accéder au caractère n 'dans une chaîne pour que cela soit une considération clé.

John Parker
la source
9

Cela variera en fonction des ressources, mais vous pouvez exécuter le script ci-dessous et voir par vous-même;)

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

Quelques références (sur une ancienne machine 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

Il semble que l'utilisation des opérateurs []ou {}soit plus ou moins la même chose.

Willy Stadnick
la source
2
Joli test! Quelques chiffres d'un Xeon de 3 ans: le microtime flottant moyen utilisant "array []" est 2.2427082061768E-7 le microtime flottant moyen utilisant "substr ()" est 3.9647579193115E5E-7 le microtime flottant moyen utilisant "array {}" est 2.1522283554077E-7
Ellert van Koperen
pour des mesures précises, il est préférable de faire du microtime hors de la boucle et de ne pas mélanger les différentes approches dans la même boucle.
PypeBros
1
ne pas mélanger l'exécution de testAet testBau sein des mêmes boucles signifie que vous êtes capable de détecter, par exemple, le fait que le testBcache-tueur testAest compatible avec le cache. Quand ils sont tous les deux dans la même boucle, ils sont mesurés pour avoir les mêmes timings parce que la mise en cache de testBpollué testA.
PypeBros
1
de même, j'éviterais de générer des chaînes ou des aléas dans les boucles de test et de les avoir prêtes dans un tableau à proximité.
PypeBros
1
-1; en laissant de côté le mécanisme de chronométrage douteux (il serait préférable de chronométrer de nombreuses opérations que de les chronométrer une à la fois; je craignais en lisant ceci que seul le temps pris pour faire l' microtime()appel compenserait la majeure partie du décalage horaire, bien que cela semble expérimentalement pour ne pas être vrai), il n'y a aucune raison de se soucier de la petite différence de vitesse ici. C'est une fraction d'un millionième de seconde; quand est-ce que ça va être important?
Mark Amery
6

Parlant comme un simple mortel, je resterais avec $str[0]. En ce qui me concerne, il est plus rapide de saisir le sens d' $str[0]un coup d'œil quesubstr($str, 0, 1) . Cela se résume probablement à une question de préférence.

En ce qui concerne les performances, eh bien, profil profil profil. :) Ou vous pouvez regarder le code source PHP ...

Stephen
la source
6
$str = 'abcdef';
echo $str[0];                 // a
Jakir Hossain
la source
6
-1; la question du PO était de savoir si cette syntaxe était une mauvaise pratique, et vous avez répondu en ... répétant la syntaxe, sans aucun commentaire? Ce n'est pas une réponse.
Mark Amery
5

Dans le cas de chaînes multi-octets (unicode), l'utilisation str[0]peut provoquer un problème. mb_substr()est une meilleure solution. Par exemple:

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

Quelques détails ici: Obtenez le premier caractère de la chaîne UTF-8

Sergey Burish
la source
Merci pour cette solution! si le premier caractère est unicode, [] ne fonctionnera pas
SunB
1

J'ai également utilisé cette notation auparavant, sans aucun effet secondaire et aucun malentendu. Cela a du sens - une chaîne n'est qu'un tableau de caractères, après tout.

Kaleb Brasee
la source
Non, une chaîne n'est pas un tableau de caractères (du moins car PHP utilise ces deux termes). -1.
Mark Amery
@gattsbr en interne, ils le sont, mais en ce qui concerne le modèle exposé par PHP, ils sont fondamentalement différents. L'accès à un décalage à l'aide de la notation entre crochets est à peu près la seule opération qu'ils ont en commun avec les tableaux; les fonctions de chaîne ne fonctionnent pas sur les tableaux, ni vice versa, et la syntaxe ( $arr[] = $new_element) d' ajout de tableau ne fonctionne pas sur les chaînes. En tant que tel, je ne pense pas que la conception de chaînes comme des tableaux de caractères soit utile.
Mark Amery
@markamery ferait mieux de réécrire le manuel de php.net que d'inclure une minuscule technicité.
gattsbr