Signature
str_shuffle(string $string): stringPurpose
str_shuffle() takes a string and returns a new string containing the same bytes in a random order. Of all the possible permutations of the input, one is produced. It is handy for low-stakes jobs such as scrambling a word for a puzzle, mixing the letters on a game rack, or generating throwaway test data.
It is not a security tool. The function does not produce cryptographically secure results, so never use it for passwords, tokens, invitation codes or anything that must be unguessable.
Signature
Parameters and defaults
$string: the input string. It is the only parameter and has no default value. The original string is not modified, because PHP strings are passed by value.
Return value and failure cases
The function returns the shuffled string. The result always has the same length as the input and contains exactly the same bytes, only in a possibly different order. The manual documents no special failure return value. Passing a value that cannot be used as a string, such as an array, raises a TypeError.
Because the order is random, the result may occasionally equal the input. For a short string like 'ab', that happens about half the time.
Example 1: what is guaranteed
You cannot predict the exact output, but you can test the properties that are guaranteed: same length and same collection of characters.
$original = 'abcdef';
$shuffled = str_shuffle($original);
$a = str_split($original);
$b = str_split($shuffled);
sort($a);
sort($b);
echo json_encode([
'same_length' => strlen($original) === strlen($shuffled),
'same_characters' => $a === $b,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"same_length":true,"same_characters":true}
Sorting both character lists removes the effect of the order, so the comparison checks only the contents.
Example 2: edge cases
Strings with fewer than two distinct bytes have only one possible permutation, so the result is always identical to the input.
echo json_encode([
str_shuffle(''),
str_shuffle('Z'),
str_shuffle('aaaa'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";["","Z","aaaa"]
An empty string returns an empty string, and no error is raised.
Example 3: seeding and shared state
str_shuffle() uses the global Mersenne Twister generator. That means it shares state with other functions that use it, such as mt_rand() and shuffle(). Seeding with mt_srand() makes the sequence repeatable, which is useful when you need reproducible tests or demos.
mt_srand(42);
$first = str_shuffle('abcdefghij');
mt_srand(42);
$second = str_shuffle('abcdefghij');
echo json_encode([
'repeatable' => $first === $second,
'length' => strlen($first),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"repeatable":true,"length":10}
The example compares the two results rather than printing them, so it does not depend on the exact permutation.
Edge cases
- Byte-based behaviour: the function works on bytes, not characters. With ASCII text this is the same thing. With UTF-8 text, a character such as
étakes more than one byte, and shuffling can separate those bytes and produce an invalid string. For multibyte text, split into characters withmb_str_split()orpreg_split('//u', ...), shuffle the array, then join it again. - Repeated characters: duplicates are kept. Shuffling
'aab'can only yield'aab','aba'or'baa'. - Identical output: a shuffle is allowed to return the original order. Do not write code that assumes the result differs from the input.
- Global state: any call advances the global generator, so adding an unrelated shuffle call can change later seeded results.
Common mistakes
- Using it for secrets. The manual says the result must not be used where values need to be unguessable. For secure randomness, use
random_int(),random_bytes(), orRandom\RandomizerwithRandom\Engine\Secure. - Expecting a unique result. Shuffling does not guarantee a different order, and it does not create unique values across calls.
- Testing exact output without seeding. A test that compares against a fixed shuffled string will fail intermittently. Test length and character counts, or seed the generator and compare two runs.
- Shuffling multibyte text directly. This can corrupt UTF-8 sequences. Split by character first.
- Forgetting to use the return value.
str_shuffle($text);on its own does nothing useful, because the input is not changed in place. - Assuming isolated randomness. The shared global generator means seeding in one place can affect shuffles elsewhere in the same request.
The manual also recommends preferring Random\Randomizer methods in newly written code. For this task, Random\Randomizer::shuffleBytes() provides the byte-wise permutation, and you can choose the engine explicitly.
Related functions
shuffle(): shuffles an array in place.Random\Randomizer::shuffleBytes(): byte-wise permutation of a string with a selectable engine.Random\Randomizer::shuffleArray(): permutation of an array.str_split()andmb_str_split(): split a string into pieces before shuffling.mt_srand(): seeds the global Mersenne Twister generator.random_int()andrandom_bytes(): secure random values.
Recap
str_shuffle() returns a randomly permuted copy of a string with the same length and bytes. It is simple and convenient for games and test data, but it works on bytes, shares global generator state, and is not secure. Test its guaranteed properties rather than exact output, and reach for Random\Randomizer or the secure random functions when quality of randomness matters.
Tested examples
$original = 'abcdef';
$shuffled = str_shuffle($original);
$a = str_split($original);
$b = str_split($shuffled);
sort($a);
sort($b);
echo json_encode([
'same_length' => strlen($original) === strlen($shuffled),
'same_characters' => $a === $b,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"same_length":true,"same_characters":true}
echo json_encode([
str_shuffle(''),
str_shuffle('Z'),
str_shuffle('aaaa'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
["","Z","aaaa"]
mt_srand(42);
$first = str_shuffle('abcdefghij');
mt_srand(42);
$second = str_shuffle('abcdefghij');
echo json_encode([
'repeatable' => $first === $second,
'length' => strlen($first),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"repeatable":true,"length":10}