Hi internals,
I propose adding a preserve_key_types parameter to array_keys()
to address
issues caused by automatic conversion of string-numeric keys to integers.
Developer Experience Considerations
While PHP's automatic conversion of numeric string keys to integers is
documented behavior, real-world usage shows this feature continues to cause
unexpected issues:
Cognitive Burden
As observed in a Reddit discussion:
"We understand the type coercion rules, but when converting '123' to 123
still catches us off guard when debugging some problems."
As we mentioned earlier, the array_keys methodProduction Risks
The implicit conversion creates hidden pitfalls:
php
复制
// Cache system failure example$cache = ["123" => "data"]; // Redis
expects string keys$keys = array_keys($cache); // Returns [123]
(int)$redis->get($keys[0]); // Fails silently
Debugging Costs
Issues manifest only at runtime, requiring:
- Additional type validation code
- Defensive programming with array_map('strval', ...)
- Increased bug investigation time
Problem ExamplesDatabase Performance Issues
php
$orderIds = ["1001", "1002"]; // VARCHAR keys in database$keys =
array_keys($orderIds); // [1001, 1002] (unexpected
int)$db->query("SELECT * FROM orders WHERE id IN
(".implode(',',$keys).")");
→ May cause full table scans when VARCHAR indexes are ignored.
Redis Cache Failures
php
$cacheData = ["user:1001" => "data", "user:1002" => "data"];$keys =
array_keys($cacheData); // ["user:1001", "user:1002"]
(correct)$numericData = ["1001" => "data", "1002" => "data"];
$numericKeys = array_keys($numericData); // [1001, 1002] (converted to
int)$redis->mget(array_merge($keys, $numericKeys)); // Partial failure
→ Mixed key types cause silent cache misses.
Proposal
Add a 4th parameter:
php
array_keys(
array $array,
mixed $search_value = null,
bool $strict = false,
bool $preserve_key_types = false
): array
When true, maintains original key types.
Questions for Discussion
Design Considerations
- Should we provide a way to opt-out of this automatic conversion?
- Would a new parameter be preferable to a separate function (e.g.
array_keys_preserve())?
- Would a new parameter be preferable to a separate function (e.g.
Use Case Validation
- Are the database and Redis examples sufficient to justify this change?
- Are there other common use cases we should consider?
Implementation Considerations
- Should we consider making this the default behavior in a future major
version?- Are there performance implications we should evaluate?
Looking forward to your feedback.
Best regards,
[xiaoma]
As far as I know, this is how array keys are designed and changing
array_keys wouldn't solve the problem. The key is converted to the
appropriate type during creation. Array keys are defined as string|int
and expecting the values to be either string or int is a programming
error. Static analysis tools should catch that out.
If a developer remembers to use preserve_key_types then they would
also remember that the key can be string|int and would design the rest
of the code accordingly. So it seems to me like this solution is not
the right one.
I sympathise with the problem and I would prefer that the array keys
keep the type with which they were created. I have seen so many times
when a developer did something like this:
$arr = ['123' => 'foo'];
foreach ($arr as $key => $index) {
echo htmlentities($key);
}
Do I remember correctly that it was because of backwards compatibility
issues that this could not be changed?
As Kamil mentioned, this is not limited to a single function but to
array type as a whole. See previous discussion
https://externals.io/message/116735.
I propose adding a |preserve_key_types| parameter to |array_keys()| to
address issues caused by automatic conversion of string-numeric keys
to integers.