← PHP array_push() 函数:向数组末尾追加元素的正确姿势 PHP range()函数:快速生成区间数组的实战教程 →

PHP array_rand()函数:从数组中随机抽取键名的实用教程

著
原创 2026-10-08 PHP 已有人查阅

一、array_rand()到底返回什么

初学者看手册容易产生一个误解:以为array_rand()返回的是数组里的值。实际上它返回的是键名。想拿到值,还得用返回的键去原数组里取一次。

这个设计并不多余。返回键名意味着你既可以通过键拿到值,也可以保留键名本身的业务含义,比如用用户ID做键时,抽出来的就是ID。理解这一点,后面的用法就顺了。

二、函数原型与参数

array_rand(array $array, int $num = 1): mixed
参数 说明 是否必需
array 待抽取的数组 必需
num 抽取的键名个数,默认为1 可选

返回值规则:

  • $num=1或不传时,返回一个键名,类型可能是int或string。

  • $num>1时,返回一个包含多个键名的数组,元素顺序是随机的。

  • $num超过数组长度时,会触发E_WARNING并返回null。

  • $num=0时会触发E_WARNING并返回null。

内部实现上,array_rand()使用的是伪随机数生成器,和rand()、mt_rand()属于同一类,不适合用于密码、令牌、验证码等安全场景。涉及安全的随机数要用random_int()或random_bytes()。

三、抽取一个键与抽取多个键的差异

抽取一个键时,返回的是标量:

<?php
$fruit = array("a" => "apple", "b" => "ball", "c" => "cat", "d" => "dog");
print_r(array_rand($fruit, 1));

输出类似:

b

抽取多个键时,返回的是数组:

<?php
$lang = array('php', 'java', 'python', 'ruby');
$randKeys = array_rand($lang, 2);
echo $lang[$randKeys[0]] . "\n";
echo $lang[$randKeys[1]] . "\n";

输出类似:

php
ruby

这里有个细节:$num>1时返回的键名数组,其内部顺序是随机的,不要假设第一个键就是原数组里下标小的那个。抽取多个键时不会重复,相当于无放回抽样。

四、关联数组下的表现

关联数组抽取返回的是字符串键:

<?php
$score = array("sachin" => "200", "rohit" => "300", "rahul" => "270");
print_r(array_rand($score, 2));

输出类似:

Array ( [0] => sachin [1] => rahul )

注意返回的数组下标是0、1,值是键名。想拿分数,需要$score[$randKeys[0]]这样取值。项目里如果直接把array_rand()的结果当值用,会得到键名而不是分数,这是新手常犯的错误。

五、与shuffle()、mt_rand()的对比

函数 用途 是否改变原数组 返回内容
array_rand() 随机抽取若干键名 否 键名或键名数组
shuffle() 打乱整个数组顺序 是 bool
mt_rand() 生成随机整数 否 int

选择原则:

  • 只需要从数组里挑几个元素,用array_rand()。

  • 需要把整个数组顺序打乱,用shuffle()。

  • 从固定范围内取随机整数,用mt_rand()。

个人经验:曾经在一个"随机推荐三个商品"的需求里,同事先用shuffle()把整个商品列表打乱,再取前三个。商品列表有几千条,每次请求都要重排整个数组,性能浪费明显。改成array_rand()抽三个键名再去取值,开销小了很多。打乱是全局操作,抽样是局部操作,需求是抽样就别用打乱。

六、项目实例

实例一:代码号学习编程·随机抽一道题

<?php
$questions = [
    'q1' => 'PHP 中 array_push 的返回值是什么?',
    'q2' => 'array_rand 返回的是键还是值?',
    'q3' => 'unset 后追加元素,键名会补位吗?',
];

$key = array_rand($questions);
echo $questions[$key];

这种单题抽取用默认的$num=1就够了,返回标量键名,取值直接。

实例二:代码号学习编程·随机展示三个标签

<?php
$tags = ['php', 'mysql', 'redis', 'nginx', 'docker', 'git'];
$randKeys = array_rand($tags, 3);

foreach ($randKeys as $k) {
    echo $tags[$k] . "\n";
}

抽取三个不重复的标签。注意$num不能超过数组元素个数,否则会报警告。

实例三:代码号学习编程·带权重的抽奖思路

array_rand()本身不支持权重。如果项目里需要按概率抽取,比如一等奖概率低、参与奖概率高,做法是把权重展开成重复元素:

<?php
$pool = [];
$prizes = [
    '一等奖' => 1,
    '二等奖' => 5,
    '参与奖' => 94,
];

foreach ($prizes as $name => $weight) {
    for ($i = 0; $i < $weight; $i++) {
        $pool[] = $name;
    }
}

$key = array_rand($pool);
echo $pool[$key];

这种写法直观,但池子会随权重放大。权重数值很大时,内存占用会上去,此时更适合用mt_rand()配合累计概率区间来判断。选哪种取决于权重规模和调用频率。

七、踩坑记录

坑一:把返回值直接当值用。关联数组里array_rand($arr)返回的是键,不是值。直接输出会得到键名,看起来"对",实际业务数据错了。

坑二:$num超过数组长度。传5抽3个元素的数组,PHP会发警告并返回null。上线前要加一层判断:

$num = min($num, count($array));

坑三:用于安全场景。有人拿array_rand()抽验证码、抽token,这是不合适的。它的随机源是伪随机,可预测。安全相关的随机必须换成random_int()。

坑四:以为返回顺序和原数组一致。$num>1时返回的键名数组顺序是随机的,如果业务上要求"按原数组顺序输出抽中的元素",需要自己对返回的键名排序后再取值。

八、本节课程知识要点

  1. array_rand()返回键名,不是值,取值要再查一次原数组。

  2. $num=1返回标量,$num>1返回键名数组,且不重复。

  3. $num超过数组长度会警告并返回null,使用前应做边界判断。

  4. 随机源是伪随机,不能用于密码、令牌等安全场景。

  5. 抽样用array_rand(),全局打乱用shuffle(),两者不要混用。

  6. 需要权重抽奖时,可展开权重池,或改用mt_rand()配合概率区间。

九、常见问题

问:array_rand()抽多个键会重复吗?

不会。抽取多个键时相当于无放回抽样,返回的键名互不相同。

问:空数组调用会怎样?

会触发E_WARNING,返回null。调用前应确认数组非空。

问:抽取结果每次都不一样吗?

不一定。随机本身就有概率抽到同一个键,尤其是数组元素少的时候。如果业务要求"连续两次不重复",需要自己记录上一次的结果并做排除。

问:能不能用array_rand()实现随机排序?

可以,但没必要。随机排序用shuffle()更直接。array_rand()的定位是抽样,不是排序。

← PHP array_push() 函数:向数组末尾追加元素的正确姿势 PHP range()函数:快速生成区间数组的实战教程 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号