array_map() ใน PHP

array_map() เป็นฟังก์ชันที่เอาไว้รับอาเรย์เข้าไป เอามาประมวลผล value ของอาเรย์ แล้วคืนค่ากลับออกมาเป็นอาเรย์ตัวใหม่ โดยค่า index หรือ key ของอาเรย์นั้นจะคงเดิมเหมือนกับในอาเรย์ต้นฉบับ

อากิวเมนต์ตัวแรกของฟังก์ชันจะเป็น callback function ส่วนตัวถัดไปจะเป็นอาเรย์ที่ต้องการจะเอามาประมวลผล

<?php
// กรณี indexed array
$numbers = [1, 2, 3, 4, 5, 6];

$multiplied = array_map( function( $number ) {
  return $number * 2;
}, $numbers );

print_r( $multiplied ); // ได้ผลลัพธ์เป็น [2, 4, 6, 8, 10, 12];

// กรณี associative array
$fruits = [
  'banana' => 1,
  'orange' => 5,
  'apple' => 3,
];

$restocked = array_map( function( $fruit ) {
  return $fruit + 5;
}, $fruits );

print_r( $restocked );
/*
ผลลัพธ์:
[
  'banana' => 6,
  'orange' => 10,
  'apple' => 8,
]
*/

ท่าที่ผมเอามาใช้ประจำคือเอามาประมวลผล WP_Query::posts ออกมาเป็นก้อนข้อมูล ก่อนที่จะส่งไปให้เท็มเพลตใช้งาน เช่น

<?php
$movies_data = new WP_Query( [
  'post_type' => 'movies',
] );

$movies = array_map( function( $movie ) {
  return [
    'title' => $movie->post_title,
    'genre' => get_field( 'genre', $movie->ID ),
  ];
}, $movies_data );

print_r( $movies );
/*
ผลลัพธ์:
[
  [
    'title' => 'Pandorum',
    'genre' => 'Sci-fi',
  ],
  [
    'title' => 'Pearl Harbor',
    'genre' => 'Action',
  ],
]
*/

ข้อดีของการใช้ array_map() คือมันจะทำให้โค้ดเราสะอาดขึ้น ช่วยลดความสับสนเวลาเขียนโค้ด และเป็นการล็อคตัวแปรให้อยู่แค่ในสโคปของ closure function ไม่ต้องกลัวว่าจะเผลอไปเปลี่ยนค่าตัวแปรนอกฟังก์ชัน

ปกติแล้วเวลาจะลูปประมวลผลตัวแปร เรามักจะใช้ foreach กัน ซึ่งมันมีปัญหาขาประจำอย่างหนึ่งคือเผลอเอาตัวแปรเก่ามาใช้แล้วลืมรีเซ็ตค่า (ซึ่งการรีเซ็ตค่าก็ต้องประกาศตัวแปรเปล่าๆ หนึ่งบรรทัดเพิ่มเข้ามาให้โค้ดรกเล่นๆ) เช่น

<?php
// บรรทัดที่ 10
$source = [ ... something ... ];

foreach ( $data => $value ) {
  $data[] = doSomething( $value );
}

// บรรทัดที่ 120 ลืมไปแล้วว่าเคยใช้ $data แล้วลืมรีเซ็ตตัวแปร
$source = [ ... another thing ... ];

foreach ( $data => $value ) {
  $data[] = doAnother( $value ); // ผลลัพธ์ไปรวมกับ $data ที่เคยใช้ก่อนหน้านี้
}

// บรรทัด 150 รีเซ็ต $data ให่้สักหน่อย
$source = [ ... everything ... ];
$data = [];

foreach ( $data => $value ) {
  $data[] = doEverything( $value );
}

อาจจะดูเล็กน้อย แต่ผมบอกว่าเลยเรื่องหลงๆ ลืมๆ แบบนี้ สร้างบั๊กตัวโตมาหลายรอบแล้ว

และหากเราใช้ PHP 7.4 ในหลายกรณีเราสามารถทำให้โค้ดสะอาดและอ่านง่ายได้ขึ้นอีกนิดหน่อยด้วยการใช้ arrow function เช่นจากตัวอย่างข้างบน เราเขียนส่วน array_map() ใหม่ได้แบบนี้

$movies = array_map( fn( $movie ) => [
  'title' => $movie->post_title,
  'genre' => get_field( 'genre', $movie->ID ),
], $movies_data );

ทั้งนี้มีข้อควรระวังอยู่เหมือนกัน คือในกรณีที่มีข้อมูลจำนวนมาก (เช่นสักล้านตัว) array_map() จะกินใช้เวลาในการประมวลผลกว่าการใช้ foreach เพราะมันมี overhead ที่เกิดจากการเรียกใช้ callback function เพิ่มเข้ามา


Posted

in

by

Tags:

Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.