รับอักขระตัวแรกของสตริงด้วย $ str [0]


276

ฉันต้องการรับตัวอักษรตัวแรกของสตริงและฉันสังเกตเห็นว่าใช้$str[0]งานได้ดี ฉันแค่ไม่แน่ใจว่านี่เป็น 'การปฏิบัติที่ดี' หรือไม่เนื่องจากเป็นสัญกรณ์ที่มักใช้กับอาร์เรย์ ฟีเจอร์นี้ดูเหมือนจะไม่ได้รับการบันทึกไว้เป็นอย่างดีดังนั้นฉันจึงหันไปหาพวกคุณเพื่อบอกฉันว่ามันถูกต้องหรือไม่ในการใช้สัญลักษณ์นี้

หรือฉันควรจะยึดมั่นใน ol ดี ' substr($str, 0, 1)?

นอกจากนี้ฉันสังเกตเห็นว่าการจัดฟันแบบหยิก ( $str{0}) ทำงานได้ดี เกิดอะไรขึ้นกับสิ่งนั้น


5
บวก 1 สำหรับสตริงย่อย "good ol '($ str, 0, 1)"
Santiago ออกจาก SO

คำตอบ:


390

ใช่. สตริงสามารถถูกมองว่าเป็นอาร์เรย์อักขระและวิธีการเข้าถึงตำแหน่งของอาเรย์คือการใช้[]โอเปอเรเตอร์ โดยปกติแล้วจะไม่มีปัญหาในการใช้งาน$str[0](และฉันค่อนข้างแน่ใจว่าเร็วกว่าsubstr()วิธีการมาก)

มีเพียงหนึ่งข้อแม้กับทั้งสองวิธีคือพวกเขาจะได้รับเป็นครั้งแรกไบต์มากกว่าครั้งแรกที่ตัวละคร สิ่งนี้สำคัญหากคุณใช้การเข้ารหัสหลายไบต์ (เช่น UTF-8) mb_substr()หากคุณต้องการที่จะสนับสนุนว่าการใช้งาน คุณควรสมมติว่าอินพุตหลายไบต์ทุกวันดังนั้นนี่เป็นตัวเลือกที่ดีที่สุดแต่จะช้าลงเล็กน้อย


7
PHP $ str [0] คำนึงถึงว่าสามารถมีตัวอักษรยาว 2Byte ได้หรือไม่? UTF และเช่นนี้? (แม้ว่า substr () ก็ไม่ได้ช่วยอะไรด้วย!)
Tomer W

77
ถ้าคุณต้องการที่จะปลอดภัยเป็นพิเศษสุดคุณควรไปด้วยmb_substr($str, 0, 1, 'utf-8')ดังนั้นคุณจะไม่ตัดทอนสตริงหลายไบต์
Vic

18
แม้ว่าจะสั้นกว่าและจำได้ง่ายกว่าsubstr($str, 0, 1)แต่ก็สับสนว่าใครอ่านรหัส
trante

10
ตัวเลือกระหว่าง square-brackets และ substr () ส่วนใหญ่เป็นเรื่องของการตั้งค่า แต่โปรดทราบว่าผลลัพธ์จะแตกต่างกันเมื่อนำไปใช้กับสตริงที่ว่างเปล่า ถ้า $ s = "" ดังนั้น $ s [] === "" แต่เป็น substr ($ s, 0, 1) === false
xtempore

9
ถ้า $ s = "" ดังนั้น $ s [0] จะสร้าง "ข้อสังเกต: สตริงที่ไม่ได้กำหนดค่าเริ่มต้น: 0" โดยที่ substr ($ s, 0, 1) จะไม่
chris

46

ไวยากรณ์ {} เลิกใช้แล้วตั้งแต่ PHP 5.3.0 แนะนำให้ใช้วงเล็บเหลี่ยม


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: ที่ลิงค์ที่คุณให้ฉันสังเกตเห็นว่าพวกเขาลบบันทึกในคู่มือ PHP พวกเขาทิ้งไว้เท่านั้น: Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose.ดังนั้นฉันสงสัยว่าพวกเขาตัดสินใจว่าการใช้{}ไม่ได้เลิกใช้อีกต่อไปตั้งแต่ PHP 6
Marco Demaio

1
@MarcoDemaio ตอนนี้ลิงค์บอกสิ่งที่ MichaelMorton พูด
Tino

1
"ไม่มีการบ่งชี้ถึงการเลิกใช้" - อันที่จริงข้อความการคัดค้านได้ถูกลบออกในการแก้ไข 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

ณ วันนี้ (10 พ.ค. 18) ข้อความจากPHP เอกสารที่ชอบ: Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose. ดูเหมือนว่ารูปแบบนี้จะคงอยู่ชั่วขณะหนึ่ง
Fr0zenFyr

25

สมมติว่าคุณต้องการถ่านตัวแรกจากส่วนหนึ่งของ $ _POST ให้เรียกมันว่า 'type' และ $ _POST ['type'] ในปัจจุบันคือ 'การควบคุม' หากในกรณีนี้ถ้าคุณใช้$_POST['type'][0]หรือsubstr($_POST['type'], 0, 1)คุณจะได้รับCกลับ

แต่ถ้าฝั่งไคลเอ็นต์มีการปรับเปลี่ยนข้อมูลที่พวกเขาส่งคุณจากtypeไปtype[]เช่นและแล้วส่ง 'ควบคุม' และ 'ทดสอบ' เป็นข้อมูลสำหรับอาร์เรย์นี้$_POST['type'][0]ตอนนี้จะกลับมาControlมากกว่าCในขณะที่substr($_POST['type'], 0, 1)จะเพียงแค่ล้มเหลว

ดังนั้นใช่อาจมีปัญหากับการใช้$str[0]งาน แต่ขึ้นอยู่กับสภาพแวดล้อมโดยรอบ


2
เพื่อเป็นการหลีกเลี่ยงปัญหานี้และในกรณีใดกรณีหนึ่งควรทำการตรวจสอบความถูกต้องของข้อมูลเสมอ if (true === is_string($_POST['type']))
fyrye

13

ข้อสงสัยเพียงอย่างเดียวของฉันคือการใช้เทคนิคนี้ในสายอักขระแบบหลายไบต์ แต่ถ้าไม่ใช่ข้อพิจารณาฉันก็สงสัยว่าคุณจะได้รับความคุ้มครอง (หากมีข้อสงสัยmb_substr()ดูเหมือนว่าจะเป็นทางเลือกที่ปลอดภัยอย่างเห็นได้ชัด)

อย่างไรก็ตามจากมุมมองของภาพรวมฉันต้องสงสัยว่าคุณจำเป็นต้องเข้าถึงตัวละคร 'n'th บ่อยแค่ไหนในสตริงเพื่อให้สิ่งนี้เป็นข้อพิจารณาที่สำคัญ


9

มันจะแตกต่างกันไปขึ้นอยู่กับทรัพยากร แต่คุณสามารถเรียกใช้สคริปต์ร้องและดูด้วยตัวคุณเอง;)

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

หมายเลขอ้างอิงบางอย่าง (บนเครื่อง 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

ดูเหมือนว่าการใช้ตัวดำเนินการ[]หรือ{}ตัวดำเนินการเหมือนกันไม่มากก็น้อย


2
เยี่ยมมาก! ตัวเลขบางตัวจาก Xeon อายุ 3 ปี: microtime เฉลี่ยที่ใช้ "array []" คือ 2.2427082061768E-7 microtime เฉลี่ยที่ใช้ "substr ()" คือ 3.9647579193115E-7 microtime เฉลี่ยที่ใช้ "array {}" คือ 2.1522283554077E-7
Ellert van Koperen

สำหรับการวัดที่แม่นยำคุณควรทำ microtime จากวงให้ดีขึ้นและอย่าผสมวิธีการต่าง ๆ ในวงเดียวกัน
PypeBros

1
ไม่ผสมการประมวลผลtestAและtestBภายในลูปเดียวกันหมายความว่าคุณสามารถตรวจจับได้เช่นความจริงที่ว่าtestBแคชนักฆ่าในขณะที่testAเป็นมิตรกับแคช เมื่อพวกเขาทั้งสองอยู่ในวงเดียวกันพวกเขาจะถูกวัดให้มีการกำหนดเวลาที่เหมือนกันเพราะแคชของtestBมลพิษ testA
PypeBros

1
ในทำนองเดียวกันฉันจะหลีกเลี่ยงการสร้างสตริงหรือแรนด์ในลูปการทดสอบและเตรียมให้พร้อมในอาเรย์ใกล้เคียง
PypeBros

1
-1; ปล่อยให้กลไกการจับเวลาสงสัย (มันจะดีกว่าที่จะดำเนินการหลายครั้งกว่าเวลาพวกเขาทีละครั้งฉันกังวลเมื่ออ่านนี้ว่าเพียงเวลาที่ใช้ในการmicrotime()โทรจะทำให้ความแตกต่างของเวลามากที่สุดถึงแม้ว่าการทดลองที่ดูเหมือนว่า ไม่ใช่ความจริง) ไม่มีเหตุผลที่จะสนใจความเร็วที่ต่างกันเล็กน้อย มันเป็นเศษเสี้ยวของหนึ่งในล้านของวินาที เมื่ออยู่ในนี้เคยไปเรื่อง?
Mark Amery

6

ฉันจะพูดด้วยความเป็นมนุษย์$str[0]เท่านั้น เท่าที่ผมห่วงก็เร็วจะเข้าใจความหมายของการได้อย่างรวดเร็วกว่า$str[0] substr($str, 0, 1)เรื่องนี้อาจเดือดลงไปเป็นเรื่องของการตั้งค่า

เท่าที่ประสิทธิภาพดำเนินไปได้ดีโปรไฟล์โปรไฟล์ :) หรือคุณสามารถเพ่งดูซอร์สโค้ด PHP ...


6
$str = 'abcdef';
echo $str[0];                 // a

6
-1; คำถามของ OP คือว่าไวยากรณ์นี้เป็นแนวปฏิบัติที่ไม่ดีหรือไม่และคุณตอบกลับโดย ... ทำซ้ำไวยากรณ์โดยไม่มีคำอธิบายใด ๆ นี่ไม่ใช่คำตอบ
Mark Amery

5

ในกรณีของสตริงที่ใช้หลายไบต์ (ยูนิโค้ด) str[0]อาจทำให้เกิดปัญหาได้ mb_substr()เป็นทางออกที่ดีกว่า ตัวอย่างเช่น:

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

รายละเอียดบางอย่างที่นี่: รับอักขระตัวแรกของสตริง UTF-8


ขอบคุณสำหรับการแก้ปัญหานี้! ถ้าตัวละครตัวแรกเป็นยูนิโค้ด [] จะไม่ทำงาน
SunB

1

ฉันเคยใช้สัญลักษณ์นั้นมาก่อนเช่นกันโดยไม่มีผลข้างเคียงที่ไม่ดีและไม่มีความเข้าใจผิด มันสมเหตุสมผลแล้ว - สตริงเป็นเพียงอาร์เรย์ของตัวละครเท่านั้น


ไม่สตริงไม่ได้เป็นอาเรย์ของตัวละคร (อย่างน้อยก็เพราะ PHP ใช้คำสองคำนี้) -1
Mark Amery


@gattsbr ภายในพวกเขา แต่เท่าที่แบบที่ PHP เผยออกมามันเป็นสิ่งที่แตกต่างกันโดยพื้นฐาน การเข้าถึงออฟเซ็ตโดยใช้เครื่องหมายวงเล็บเหลี่ยมเป็นวิธีการเดียวที่พวกเขามีร่วมกับอาร์เรย์ ฟังก์ชั่นสตริงไม่ทำงานในอาร์เรย์หรือ vica ในทางกลับกันและอาร์เรย์ผนวกไวยากรณ์ ( $arr[] = $new_element) ไม่ทำงานบนสตริง เช่นนี้ฉันไม่คิดว่าการตั้งค่าสตริงเนื่องจากอาร์เรย์อักขระมีประโยชน์
Mark Amery

@markamery ให้ดียิ่งขึ้นในการเขียนคู่มือ php.net ใหม่เพื่อรวมเอาวิชาเทคนิคจิ๋ว
gattsbr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.