O PHP foi projetado (ou melhor, evoluído) para uso com solicitações da Web, nas quais você frequentemente lida com a entrada de string (parâmetros de URL ou solicitações POST de um formulário em um navegador). Como tal, ele converterá automaticamente seqüências para outros tipos.
Um exemplo simples disso é que '1' + '2'fornece 3, não um erro, ou '12'ou alguma outra interpretação. Pela mesma lógica, a cadeia '0'pode ser usada como numérica 0.
Enquanto isso, como muitas linguagens, o PHP trata certos valores como "falsy" quando convertidos em booleanos - aqueles que são intuitivamente "vazios", como você diz. Isso inclui numérico 0, bem como a sequência vazia ''e a matriz vazia []. Em uma ifdeclaração, a expressão é explicitamente convertida em booleana, e if ( 0 )é a mesma que if ( false ).
Ao juntar essas duas coisas, você obtém um enigma: por um lado, como você diz, '0'é uma string não vazia; por outro lado, dissemos que ele pode ser usado como numérico 0, que é "vazio". O PHP opta por tratar o "zero-ness" como mais importante que o "rigor", de modo que '0'é considerado "falso".
Em suma '0' == 0 == false:; ou(bool)'0' === (bool)(int)'0'