Internally PHP stores variables (zend_array* symbol_table) in a same data structure that is used for arrays. This allows you to have variable names with the same constraints as array keys.
Eg. Zend API function zend_set_local_var sets a value to symbol table using zend_hash_update, which is a function used to manipulate PHP array types as well.
We can't however allow every character in variable names in PHP source code. That's because lexical analysis must distinguish labels from other tokens. Variable variables offer a workaround for this.
It's not a bug nor a way to abuse anything. That being said, the documentation states that all labels, including variables, must have a regex form [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*, so i wouldn't rely on having arbitrary characters in variable names.
What ${'0'} = 1; actually does, it sets value 1 to the current scope's symbol table at key 0.
You can get that particular table with get_defined_vars function.
Looking at the source code, we'll see that the function just copies the current symbol table and returns it to caller.
PHP extract function (src) actually checks that keys have a valid label format (by calling php_valid_var_name), so you can't generate variables with funky names using that.
Anyway, even though it's possible to create variables of any name using variable variable syntax (even a variable with no name ${''}), i think it's bad practice. Even worse if a library expects or enforces you to do so. Saying it's a workaround might be a bit overstatement actually. Maybe it should be considered as an implementation detail and an undocumented feature.
$0. It looks like it's a variable called${'0'}. Is it possible to access the variable by calling$0?$aby using${'a'}, so one would assume that the existence of${'0'}indicates the existence of$0(even if we can't access it this way). In other words, it seems as if PHP can very well handle$0, but just can't parse it.