Hàm coalesce cho PHP?


131

Nhiều ngôn ngữ lập trình có chức năng kết hợp (trả về giá trị không phải NULL đầu tiên, ví dụ ). Đáng buồn là PHP năm 2009 thì không.

Điều gì sẽ là một cách tốt để thực hiện một trong PHP cho đến khi chính PHP có một hàm kết hợp?


11
Liên quan: toán tử hợp nhất null mới ??cho PHP 7.
kojiro

Thông tin thêm về toán tử hợp nhất null có thể được tìm thấy ở đây - stackoverflow.com/questions/33666256/NH
Peter

1
Chỉ cần lưu ý, PHP7 đã triển khai fucntion này
Grzegorz

@Grzegorz: Một toán tử không phải là một hàm hoặc bạn đã tìm thấy hàm đó mới ở đâu trong PHP 7;)
hakre

Theo chức năng tôi không có nghĩa là chức năng;) Tính năng. Tôi đã không chính xác. Cảm ơn bạn :)
Grzegorz

Câu trả lời:


194

Có một toán tử mới trong php 5.3 thực hiện điều này: ?:

// A
echo 'A' ?: 'B';

// B
echo '' ?: 'B';

// B
echo false ?: 'B';

// B
echo null ?: 'B';

Nguồn: http://www.php.net/ChangeLog-5.php#5.3.0


25
Thế còn nhiều phím tắt ternary, một cái gì đó như "echo $ a ?: $ B ?: $ C ?: $ D;" công việc?
ChrisR

5
Không hoạt động như mong đợi cho mảng. Ví dụ: khi cố kiểm tra xem một phần tử mảng không xác định là falsey sẽ dẫn đến lỗi. $input['properties']['range_low'] ?: '?'
Keyo

5
Bạn sẽ nhận được thông báo Chỉ mục không xác định bất kể sử dụng toán tử hợp nhất.
Kevin

2
Nhiều đối số falsey trả về đối số cuối cùng, array() ?: null ?: falsetrả về false. Các nhà điều hành thực sự lành mạnh.
Brad Koch

6
Hãy nhớ rằng điều này không chỉ chấp nhận không null giống như kết hợp trong các ngôn ngữ khác, nhưng bất kỳ giá trị nào, sẽ được chuyển đổi hoàn toàn thành boolean. Vì vậy, hãy đảm bảo bạn theo kịp các quy tắc truyền loại
DanMan

65

PHP 7 đã giới thiệu một toán tử hợp nhất thực sự :

echo $_GET['doesNotExist'] ?? 'fallback'; // prints 'fallback'

Nếu giá trị trước ??không tồn tại hoặc là nullgiá trị sau khi ??được lấy.

Sự cải thiện so với ?:toán tử được đề cập là, ??cũng xử lý các biến không xác định mà không cần ném E_NOTICE.


Cuối cùng, không còn nữa () và trống () ở khắp mọi nơi!
George Kagan

7
@timeNomad bạn vẫn sẽ cần trống, nó chỉ kiểm tra null
Nabeel Khan

Cách duy nhất để có được sự "hợp tác" an toàn là sử dụng một chút của cả hai:($_GET['doesNotExist'] ?? null) ?: 'fallback'
Nathan Baulch

Tuy nhiên, ưu điểm của ?:hơn ??là nó kết hợp các giá trị trống cũng ??không làm được. Tương tự như hành vi của toán tử OR logic trong JavaScript (nghĩa là $val || 'default'), tôi sẽ thấy đó ?:là một hình thức kết hợp thực tế hơn nếu trong thực tế, chúng ta cuối cùng thấy mình xử lý cả trốngrỗng theo cùng một cách (nghĩa là $val ?: 'default'). Và nếu bạn muốn buộc vấn đề thêm và nuốt E_NOTICE, bạn có thể tranh luận điều này ngay cả:echo @$val ?: 'default';
Matt Borja

29

Lần truy cập đầu tiên cho "php coalesce" trên google.

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
      return $arg;
    }
  }
  return NULL;
}

http://drupial.com/content/php-coalesce


9
Lưu một chút ram và không sao chép các đối số thành một mảng, chỉ cần thực hiện foreach (func_get_args () là $ arg) {}
TravisO

17
@ [Alfred, Ciaran] - bạn không chính xác. foreach () chỉ đánh giá đối số đầu tiên một lần, để lấy một mảng và sau đó lặp lại nó.
gahooa

6
Đặt func_get_args () bên trong foreach (ở đây là $ arg) sẽ không thay đổi bất cứ điều gì từ quan điểm hiệu suất.
Savageman

7
@Savageman ... chính xác ... nếu bạn đang nghĩ đến việc giảm hiệu suất mili giây này hoặc vài byte bộ nhớ ra khỏi ứng dụng của bạn, có lẽ bạn đang nhìn vào nút cổ chai hiệu năng / bộ nhớ sai
ChrisR

4
Trớ trêu thay, đây là bản hit đầu tiên cho "hợp tác php" trên Google.
Sẽ cạo râu

18

Tôi thực sự thích các nhà điều hành ?: Thật không may, nó chưa được thực hiện trên môi trường sản xuất của tôi. Vì vậy, tôi sử dụng tương đương với điều này:

function coalesce() {
  return array_shift(array_filter(func_get_args()));
}

1
đây là một sự kết hợp 'trung thực', sử dụng mảng_filter để loại bỏ mọi thứ được đánh giá là sai (bao gồm null) trong n đối số được truyền vào. Tôi đoán là sử dụng shift thay vì phần tử đầu tiên trong mảng bằng cách nào đó mạnh mẽ hơn, nhưng điều đó phần tôi không biết. xem: php.net/manual/en/ Từ
Adam Tolley

3
Tôi thích nó nhưng phải đồng ý với @hakre - coalesceđược cho là trả lại đối số không null đầu tiên mà nó gặp, bao gồm FALSE. FALSEMặc dù vậy, chức năng này sẽ loại bỏ , có lẽ không phải là những gì op có trong đầu (ít nhất không phải là những gì tôi muốn từ một coalescechức năng).
Madbreaks

1
Chỉ các biến nên được chuyển qua tham chiếu
Ben Sinclair

9

Điều đáng chú ý là do cách xử lý của PHP đối với các biến không xác định và các chỉ số mảng, bất kỳ loại hàm kết hợp nào đều được sử dụng hạn chế. Tôi rất thích có thể làm điều này:

$id = coalesce($_GET['id'], $_SESSION['id'], null);

Nhưng trong hầu hết các trường hợp, điều này sẽ khiến PHP bị lỗi với E_NOTICE. Cách an toàn duy nhất để kiểm tra sự tồn tại của một biến trước khi sử dụng nó là sử dụng nó trực tiếp trong khoảng trống () hoặc isset (). Toán tử ternary được đề xuất bởi Kevin là tùy chọn tốt nhất nếu bạn biết rằng tất cả các tùy chọn trong liên kết của bạn được biết là được khởi tạo.


Trong trường hợp này, các hiệp hội mảng hoạt động khá độc đáo ( $getstuff = $_GET+$_SESSION+array('id'=>null);$id=$getstuff['id'];).
Brilliand

@ Quill nghĩa là gì? Bạn đã có giải pháp gợi ý với tài liệu tham khảo?
Ben Sinclair

PHP 7 giới thiệu toán tử ternary mới đáng yêu ??để làm cho hoạt động rất phổ biến này ngắn gọn hơn.
botimer

6

Hãy chắc chắn rằng bạn xác định chính xác cách bạn muốn chức năng này hoạt động với một số loại nhất định. PHP có nhiều loại chức năng kiểm tra hoặc tương tự, vì vậy hãy chắc chắn rằng bạn biết chúng hoạt động như thế nào. Đây là một ví dụ so sánh giữa is_null () và blank ()

$testData = array(
  'FALSE'   => FALSE
  ,'0'      => 0
  ,'"0"'    => "0"  
  ,'NULL'   => NULL
  ,'array()'=> array()
  ,'new stdClass()' => new stdClass()
  ,'$undef' => $undef
);

foreach ( $testData as $key => $var )
{
  echo "$key " . (( empty( $var ) ) ? 'is' : 'is not') . " empty<br>";
  echo "$key " . (( is_null( $var ) ) ? 'is' : 'is not')  . " null<br>";
  echo '<hr>';
}

Như bạn có thể thấy, blank () trả về true cho tất cả những thứ này, nhưng is_null () chỉ làm như vậy cho 2 trong số chúng.


2

Tôi đang mở rộng câu trả lời được đăng bởi Ethan Kent . Câu trả lời đó sẽ loại bỏ các đối số không null đánh giá thành sai do hoạt động bên trong của mảng_filter , đây không phải là điều mà một coalescehàm thường làm. Ví dụ:

echo 42 === coalesce(null, 0, 42) ? 'Oops' : 'Hooray';

Giáo sư

Để khắc phục điều này, một đối số thứ hai và định nghĩa hàm được yêu cầu. Hàm có thể gọi được có trách nhiệm cho array_filterbiết có thêm giá trị mảng hiện tại vào mảng kết quả hay không:

// "callable"
function not_null($i){
    return !is_null($i);  // strictly non-null, 'isset' possibly not as much
}

function coalesce(){
    // pass callable to array_filter
    return array_shift(array_filter(func_get_args(), 'not_null'));
}

Sẽ thật tuyệt nếu bạn có thể đơn giản vượt qua issethoặc 'isset'làm đối số thứ 2 array_filter, nhưng không có may mắn như vậy.


0

Tôi hiện đang sử dụng tính năng này, nhưng tôi tự hỏi liệu nó có thể được cải thiện với một số tính năng mới trong PHP 5 không.

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
    return $arg;
    }
  }
  return $args[0];
}

0

PHP 5.3+, với các bao đóng:

function coalesce()
{
    return array_shift(array_filter(func_get_args(), function ($value) {
        return !is_null($value);
    }));
}

Bản trình diễn: https://eval.in/187365


Chỉ các biến nên được chuyển qua tham chiếu
Ben Sinclair

Yup, tôi đã phá vỡ các quy tắc nghiêm ngặt cho bản demo, chỉ để làm cho nó đơn giản. :)
Paulo Freitas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.