Hi Xinchen,
There is still a way we could make this work, if we'd simply check for nNumUsed == nNumOfElements as well. Because a packed array with nNumUsed equal to nNumOfElements must be consecutively indexed from zero onward without any gaps (no IS_UNDEF).
I therefore propose to change array_slice to use:
if ((Z_ARRVAL_P(input)->u.flags & HASH_FLAG_PACKED) && (!preserve_keys || (offset == 0 && Z_ARRVAL_P(input)->nNumUsed == Z_ARRVAL_P(input)->nNumOfElements)))
I think the additional check is well worth it as it is not costly per se and will only ever be performed for the case of array_slice($packed_array, 0, ..., true). It won't slow down the more common cases of array_slice($packed_array, ..., false) or array_slice($hash_array, ..., true/false).
That way we can preserve the packed charactersitic even if the input array was channelled through array_slice with preserved_keys=true, which is not that uncommon given that many APIs use wrappers around array_slice with the preserve_keys option precautiously set to true.
Let me know what you think.
Thanks,
Benjamin