source_url | revision | status | license |
---|---|---|---|
1718313707 |
wip |
- Versão: 0.1
- Data: 12/04/2024
- Pessoas autoras: Niels Dossche
- Situação: Em votação
- Primeira publicação: Wiki do PHP
O ciclo de desenvolvimento do PHP 8.4 já viu duas melhorias importantes na
extensão ext-dom
: suporte ao HTML 5 e
conformidade opcional com a especificação DOM.
Esta RFC é (provavelmente) a última melhoria da ext-dom
para o PHP
8.4: ela propõe adicionar novos recursos à extensão.
Em particular, focaremos no suporte ao seletor CSS, preenchendo recursos
ausentes, mas comuns, e adicionando novas propriedades.
Essas melhorias e alterações se aplicam apenas às novas classes no namespace
Dom
.
A RFC consiste em várias subpropostas agrupadas em uma RFC para minimizar a sobrecarga. Nesta seção, discutiremos cada proposta separadamente.
Existem várias maneiras de consultar nós em um documento XML ou HTML.
Aquela já implementada desde a existência da extensão DOM está usando XPath.
Outra forma popular, com a qual as pessoas provavelmente estão mais
familiarizadas, são os seletores CSS.
Em teoria, toda consulta que você pode escrever com seletores CSS também pode
ser escrita com XPath.
No entanto, em muitos casos, o XPath é muito mais complicado de usar.
Por exemplo, uma consulta simples como p:contains("hello") + span
é
equivalente a
.//p[contains(normalize-space(),"hello")]/following-sibling: :*[1]/self::span
.
As coisas podem ficar muito mais complicadas quando você usa pseudofunções
como :disabled
, que são muito difíceis de expressar em XPath.
A especificação DOM define as seguintes funções de seletor CSS:
namespace Dom {
interface ParentNode {
public function querySelector(string $selectors): ?Element {}
public function querySelectorAll(string $selectors): NodeList {}
}
class Element extends Node implements ParentNode {
public function closest(string $selectors): ?Element {}
public function matches(string $selectors): bool {}
}
}
Isso é o que os métodos fazem:
querySelector
: Retorna o primeiro elemento descendente que corresponde aos seletores CSS.querySelectorAll
: Retorna umaNodeList
contendo todos os elementos descendentes que correspondem aos seletores CSS.closest
: Encontra o ancestral mais próximo do elemento que corresponde aos seletores CSS.matches
: Retornatrue
se o elemento corresponder aos seletores CSS, oufalse
, caso contrário.
Vale ressaltar que os seletores CSS podem conter pseudoclasses que só fazem
sentido quando algo é renderizado na tela.
Como, por exemplo, :hover
, que corresponde quando uma pessoa usuária passa o
mouse sobre um elemento.
Como no contexto do PHP isso não faz sentido, um seletor CSS que usa tal
pseudoclasse não corresponderá a nada.
Embora seja possível implementar closest
e matches
usando XPath, isso não
pode ser feito com um bom desempenho (até onde eu sei).
A biblioteca fundamental que usamos para análise do HTML5 também contém a funcionalidade CSS necessária para implementar esses métodos. Portanto, podemos obter a funcionalidade com relativa facilidade. Eu só tive que adaptar as estruturas de dados dos nós para corresponder às estruturas de dados do PHP.
Existem soluções alternativas criadas por pessoas desenvolvedoras que implementam uma tradução de seletores CSS para XPath, mas com base no que vi:
- Elas sofrerão um impacto no desempenho porque a tradução não é "gratuita".
- Elas não fornecem uma forma eficiente de implementar
closest
ematches
. - Como elas são implementadas em torno das antigas classes DOM, e as antigas classes DOM não consideram os diferentes namespaces HTML adequadamente, elas também não consideram os namespaces adequadamente.
Exemplo 1: querySelector
$dom = Dom\XMLDocument::createFromString(<<<XML
<root>
<span>1</span>
<p>oi</p>
<span>2</span>
</root>
XML);
var_dump($dom->querySelector('p ~ span')->textContent); // string(1) "2"
Exemplo 2: closest
$dom = Dom\XMLDocument::createFromString(<<<XML
<root>
<div class="foo" xml:id="div1">
<div xml:id="div2">
<div class="bar" xml:id="div3"/>
</div>
</div>
</root>
XML);
var_dump($dom->getElementById('div3')->closest('div')->getAttribute("xml:id")); // string(4) "div3"
var_dump($dom->getElementById('div3')->closest(':not(div[class])')->getAttribute("xml:id")); // string(4) "div2"
Exemplo 3: matches
$dom = Dom\XMLDocument::createFromString(<<<XML
<root>
<div xml:id="div1">
<div xml:id="div2">
<div xml:id="div3"/>
</div>
</div>
</root>
XML);
var_dump($dom->getElementById('div3')->matches('div > div')); // bool(true)
var_dump($dom->getElementById('div3')->matches('root > div')); // bool(false)
Esta é uma propriedade da classe Element
definida na
especificação DOM:
namespace Dom {
class Element /* ... */ {
public string $innerHTML;
}
}
A leitura deste campo obterá a serialização do conteúdo interno do elemento, a
gravação nele transformará uma string em uma subárvore e substituirá o
conteúdo do elemento pela nova subárvore.
Se o documento for um documento HTML, o analisador/serializador HTML será usado.
Se o documento for um documento XML, o analisador/serializador XML será usado.
Sim, isso significa que innerHTML pode definir conteúdo XML, e isso foi
definido pelas especificações.
Esse erro na nomenclatura é uma bagagem herdada da especificação que decorre
do fato de que, por questões de interoperabilidade, a classe
Element
é compartilhada entre documentos XML e HTML.
Se a serialização não estiver bem formada para XML, uma
DOMException
com $code
DOM_SYNTAX_ERR
será lançada, conforme definido pela
especificação.
A análise de documentos (ou fragmentos) pode causar erros hard/soft.
Os erros soft são relatados por meio de alertas ou, se o mecanismo interno de
tratamento de erros for usado, os erros serão armazenados em um array.
A menos que LIBXML_NOERROR
seja fornecida, nesse caso
esses erros soft serão silenciados.
Observe que não temos como fornecer uma opção de análise para a propriedade
innerHTML
e, portanto, não podemos fornecer uma maneira de silenciar os erros
de maneira limpa.
Perguntei sobre isso na lista de discussão, mas não obtive
resposta.
Isso provavelmente significa que as pessoas estão inseguras ou não se importam
e, por isso, optei por não implementar o relatório de erros porque é mais fácil
omitir algo e adicioná-lo mais tarde do que remover algo mais tarde.
Proponho a adição de várias novas propriedades à classe
Document
para tornar o desenvolvimento um pouco mais fácil:
namespace Dom {
class HTMLElement extends Element {
/* Há uma oportunidade de adicionar propriedades úteis da especificação
HTML aqui no futuro. */
}
class Document /* ... */ {
public ?HTMLElement $body;
/** @readonly */
public ?HTMLElement $head;
public string $title;
}
}
Essas adições são descritas no adendo da especificação HTML para o DOM.
As propriedades devem ser relativamente autoexplicativas.
$body
refere-se ao elemento body
(se houver), $head
ao elemento head
(se houver) e $title
ao texto dentro do elemento title
(que por sua vez está
dentro do elemento head
).
Você pode ler sobre todos os detalhes usando o link acima, porque é um pouco
mais complicado quando SVG está envolvido, por exemplo, mas você deve estar
familiarizado com essas propriedades do Javascript.
Como você pode ver, isso também requer a adição da classe HTMLElement
.
Esta classe estende a classe Element
.
No futuro, poderemos adicionar propriedades a elas também, mas isso será deixado
de fora desta RFC por enquanto.
Os elementos que estão dentro do namespace HTML
agora retornarão uma
instância de HTMLElement
em vez de Element
.
Por exemplo, $documentElement
é uma propriedade na classe
Document
do tipo Element
.
Se este for um elemento HTML, obteremos uma instância de HTMLElement
em vez de
Element
.
Tudo isso está definido nas especificações.
Proponho adicionar a
classe TokenList
da especificação DOM ao PHP:
namespace Dom {
/**
* @not-serializable
* @strict-properties
*/
final class TokenList implements \IteratorAggregate, \Countable {
private function __construct() {}
/** @readonly */
public int $length;
public function item(int $index): ?string {}
public function contains(string $token): bool {}
public function add(string ...$tokens): void {}
public function remove(string ...$tokens): void {}
public function toggle(string $token, ?bool $force = null): bool {}
public function replace(string $token, string $newToken): bool {}
public function supports(string $token): bool {}
public string $value;
public function count(): int {}
public function getIterator(): \Iterator {}
}
}
Uma instância de TokenList
pode ser obtida através da propriedade
Element::$classList
.
Por enquanto, seu propósito está limitado a gerenciar os nomes das classes de um
elemento, mas a classe é construída para representar um conjunto de tokens.
Superficialmente, pode parecer trivial gerenciar os nomes de classes em
documentos, mas isso não é bem verdade.
TokenList
considerará as classes como um conjunto, lidará com normalização de
espaços em branco, iteração, manipulações fáceis como alternância, etc., tudo
disponível para você em uma API fácil de usar.
Exemplo 1: Operações básicas
$dom = Dom\XMLDocument::createFromString("<root class='primeiro segundo\tterceiro'/>");
$root = $dom->documentElement;
$list = $root->classList;
var_dump($list);
/*
object(Dom\TokenList)#3 (2) {
["length"]=>
int(3)
["value"]=>
string(25) "primeiro segundo terceiro"
}
*/
var_dump($list->contains("segundo")); // bool(true)
var_dump($list->toggle("segundo")); // bool(false)
var_dump($root->className); // string(17) "primeiro terceiro"
$list->replace("terceiro", "outra-classe");
var_dump($list->item(1)); // string(12) "outra-classe"
A extensão DOM já implementa algumas extensões específicas do PHP para as classes DOM, como suporte à normalização e canonização. Para melhor suportar algumas cargas de trabalho, proponho as seguintes adições específicas do PHP:
namespace Dom {
/**
* @not-serializable
* @strict-properties
*/
final class NamespaceInfo
{
public readonly ?string $prefix;
public readonly ?string $namespaceURI;
public readonly Element $element;
private function __construct() {}
}
class Attr /* ... */ {
public function rename(?string $namespace, string $qualifiedName): void {}
}
class Element /* ... */ {
public string $substitutedNodeValue;
/** @return list<NamespaceInfo> */
public function getInScopeNamespaces(): array {}
/** @return list<NamespaceInfo> */
public function getDescendantNamespaces(): array {}
public function rename(?string $namespace, string $qualifiedName): void {}
}
}
Vamos examiná-las uma por uma.
Esta classe é a substituta moderna da classe
DOMNamespaceNode
.
DOMNamespaceNode
foi mal projetada porque tenta ser um
Node
, mas, na verdade, não é um nó porque não está na árvore.
Por exemplo, no "DOM antigo", ao usar getAttributeNode("xmlns")
, ele pode
retornar um DOMNamespaceNode
para a declaração de
namespace, mesmo que não exista necessariamente tal atributo.
A outra maneira de obter uma instância
DOMNamespaceNode
é via XPath usando o eixo
namespace::*
.
A razão pela qual retornamos a instância
DOMNamespaceNode
para o XPath é devido a algumas regras peculiares estabelecidas pela
Recomendação do XPath.
Em particular, o eixo de namespace precisa retornar todos os namespaces em
escopo de um elemento.
No entanto, esse link da especificação também afirma:
Os elementos nunca compartilham nós de namespace: se um nó de elemento não for o mesmo nó que outro nó de elemento, então nenhum dos nós de namespace de um nó de elemento será o mesmo nó que os nós de namespace de outro nó de elemento.
Por isso, não podemos retornar o nó de atributo correspondente à declaração do
namespace (se houver) porque teríamos que retornar o mesmo nó de atributo
para elementos diferentes.
Consequentemente, o DOMNamespaceNode
é retornado no
"DOM antigo".
No entanto, implementar isso no "novo DOM" é um problema porque estaríamos
retornando algo de uma consulta XPath que não é um nó.
Isso é confuso para as pessoas usuárias e também para as ferramentas de análise
estática.
Como essas APIs também são implementadas por navegadores, vale a pena ver como eles resolvem esse problema e o que diz a especificação. Acontece que tudo isso não está documentado nas especificações e os navegadores não implementam o eixo de namespace.
Proponho adicionar dois métodos ao "novo DOM" que substituem a funcionalidade do
eixo de namespace: getInScopeNamespaces
, que substitui ./namespace::*
e
getDescendantNamespaces
, que substitui .//namespace::*
.
Quando as pessoas usuárias tentarem consultar nós de namespace a partir do
eixo de namespace em Dom\XPath
, lançaremos uma
DOMException
com $code
DOM_NOT_SUPPORTED_ERR
, redirecionando as pessoas
usuárias para usar um desses dois métodos.
Para identificar um namespace, precisamos apenas saber o prefixo, o URI e o
elemento com escopo definido.
Portanto, ele possui esses três campos.
Só pode ser construído pela extensão DOM, não pelas pessoas usuárias.
Nenhuma propriedade específica do nó será implementada em NamespaceInfo
.
As principais vantagens são:
- A garantia de que as consultas XPath para nós sempre retornarão nós.
- Melhores resultados de análise estática.
- Menos confusão para as pessoas usuárias.
$dom = Dom\XMLDocument::createFromString(<<<XML
<root xmlns="urn:a">
<b:sibling xmlns:b="urn:b" xmlns:d="urn:d" d:foo="bar">
<d:child xmlns:d="urn:d2"/>
</b:sibling>
</root>
XML);
$sibling = $dom->documentElement->firstElementChild;
var_dump($sibling->getInScopeNamespaces());
var_dump($sibling->getDescendantNamespaces());
Exemplo: saída de getInscopeNamespaces()
array(3) {
[0]=>
object(Dom\NamespaceInfo)#2 (3) {
["prefix"]=>
NULL
["namespaceURI"]=>
string(5) "urn:a"
["element"]=> ...
(<b:sibling>)
}
[1]=>
object(Dom\NamespaceInfo)#4 (3) {
["prefix"]=>
string(1) "b"
["namespaceURI"]=>
string(5) "urn:b"
["element"]=> ...
(<b:sibling>)
}
[2]=>
object(Dom\NamespaceInfo)#5 (3) {
["prefix"]=>
string(1) "d"
["namespaceURI"]=>
string(5) "urn:d"
["element"]=> ...
(<b:sibling>)
}
}
Exemplo: saída de getInScopeNamespaces()
array(6) {
[0]=>
object(Dom\NamespaceInfo)#5 (3) {
["prefix"]=>
NULL
["namespaceURI"]=>
string(5) "urn:a"
["element"]=> ...
(<b:sibling>)
}
[1]=>
object(Dom\NamespaceInfo)#4 (3) {
["prefix"]=>
string(1) "b"
["namespaceURI"]=>
string(5) "urn:b"
["element"]=> ...
(<b:sibling>)
}
[2]=>
object(Dom\NamespaceInfo)#2 (3) {
["prefix"]=>
string(1) "d"
["namespaceURI"]=>
string(5) "urn:d"
["element"]=> ...
(<b:sibling>)
}
[3]=>
object(Dom\NamespaceInfo)#6 (3) {
["prefix"]=>
NULL
["namespaceURI"]=>
string(5) "urn:a"
["element"]=> ...
(<d:child>)
}
[4]=>
object(Dom\NamespaceInfo)#8 (3) {
["prefix"]=>
string(1) "b"
["namespaceURI"]=>
string(5) "urn:b"
["element"]=> ...
(<d:child>)
}
[5]=>
object(Dom\NamespaceInfo)#9 (3) {
["prefix"]=>
string(1) "d"
["namespaceURI"]=>
string(6) "urn:d2"
["element"]=> ...
(<d:child>)
}
}
No "DOM antigo", a propriedade $nodeValue
realizava a
substituição de entidade, o que vai contra as especificações e pode causar
problemas de segurança.
No "novo DOM", $nodeValue
não substitui entidades (conforme
pretendido pelas especificações).
No entanto, isso significa que não podemos mais substituir entidades de
propósito.
Este não é o caso de uso mais comum, mas às vezes é necessário ao lidar com XML
que você confia.
A propriedade $substitutedNodeValue
será o valor do nó, mas com a substituição
de entidade explicitamente habilitada.
Exemplo 1: Definir o valor substituído em uma entidade nativa
$dom = Dom\XMLDocument::createFromString('<root/>');
$root = $dom->documentElement;
$root->substitutedNodeValue = "&";
var_dump($root->textContent); // string(1) "&"
// Nota: isso irá escapar a entidade conforme as regras de serialização do XML.
echo $dom->saveXml(); // <root>&</root>
Esse método é apenas parcialmente específico do PHP. Ele existia no DOM Core Level 3, mas nunca foi implementado no PHP. Ele não existe mais no padrão atual: os autores o removeram para simplificar a API e acho que também porque a especificação DOM é mais centrada em HTML hoje em dia do que em XML. Propomos algo muito semelhante ao que existia nas especificações, mas ligeiramente melhorado.
Às vezes é necessário alterar um prefixo de namespace para um
elemento/atributo, alterar o nome de um elemento/atributo ou alterar seu URI de
namespace.
Este caso de uso ocorre ao combinar diferentes documentos ou ao corrigir
documentos, como, por exemplo, com implementações SOAP criadas por pessoas
usuárias.
Isso pode ser feito hoje recriando toda a subárvore sob um elemento com o novo
nome, prefixo e namespace; mas isso é extremamente irritante e difícil de
acertar.
Essa abordagem também não funcionará se você tiver referências à mesma instância
de Element
, pois agora um trecho de código está
funcionando em um novo nó enquanto outros trechos de código funcionam no nó
antigo.
Acontece que alterar essas propriedades é realmente muito fácil de fazer internamente, então faz sentido apenas expor essa funcionalidade à pessoa usuária.
Você verá que o método rename segue a mesma assinatura do método
createElementNS
e também executa as mesmas verificações
de integridade relacionadas ao namespace.
Essas verificações de integridade garantem que as regras relacionadas ao
namespace sejam atendidas e, se não forem, o método lançará uma
DOMException
do tipo
NAMESPACE_ERR
(ou INVALID_CHARACTER_ERR
).
public function createElementNS(?string $namespace, string $qualifiedName): Element {} // Em Dom\Document
public function rename(?string $namespace, string $qualifiedName): void {} // Em Dom\Element e Dom\Attr
O primeiro argumento do método rename
permite alterar o URI do namespace do
elemento/atributo, enquanto o segundo permite alterar o nome qualificado.
O nome qualificado é a combinação do prefixo e do nome local; ou apenas o nome
local se não houver nenhum prefixo.
Você pode estar se perguntando: "Por que não dividir esse método em vários
métodos diferentes?".
A resposta é que isso não é possível: o namespace escolhido tem implicações
sobre quais nomes qualificados são permitidos.
Portanto, em alguns casos você terá que alterar esses dois simultaneamente.
É claro que é possível alterar apenas um dos dois enquanto mantém o outro
intacto, mas isso deve acontecer conforme as regras relacionadas ao namespace.
Vimos anteriormente como os elementos no namespace HTML
criarão uma
instância
de HTMLElement
em vez de Element
.
Isso impõe uma restrição à API rename
porque, caso contrário, será possível
criar um Element
no namespace HTML
ou um HTMLElement
que não esteja no namespace HTML
.
Portanto, se o elemento estiver no namespace HTML
, ele deverá permanecer
nesse namespace; e se não estiver no namespace HTML
, não poderá entrar no
namespace HTML
.
Se você tentar fazer isso, uma DOMException
com $code
DOM_INVALID_MODIFICATION_ERR
será lançada.
Exemplo 1: Operação básica em um elemento
$dom = Dom\XMLDocument::createFromString('<root/>');
$root = $dom->documentElement;
$root->rename(NULL, 'documento');
echo $dom->saveXml(); // <documento/>
$root->rename('urn:teste', 'documento');
echo $root->namespaceURI; // urn:teste
var_dump($root->prefix); // NULL
echo $dom->saveXml(); // <documento xmlns="urn:teste"/>
$root->rename('urn:teste', 'prefixo:documento');
echo $root->namespaceURI; // urn:teste
var_dump($root->prefix); // prefixo
echo $dom->saveXml(); // <prefixo:documento xmlns:prefixo="urn:teste"/>
Exemplo 2: Alterando o nome de um elemento HTML
$dom = Dom\HTMLDocument::createFromString('<p>olá</p>', LIBXML_NOERROR);
$p = $dom->getElementsByTagName('p')[0];
$p->rename($p->namespaceURI, 'span');
echo $dom->saveHTML(); // <html><head></head><body><span>olá</span></body></html>
Exemplo 3: Alterando o nome de um atributo
$dom = Dom\HTMLDocument::createFromString('<p align="center"></p>', LIBXML_NOERROR);
$p = $dom->getElementsByTagName('p')[0];
$attr = $p->getAttributeNode('align');
$attr->rename($attr->namespaceURI, 'title');
echo $dom->saveHTML(); // <html><head></head><body><p title="center"></p></body></html>
Exemplo 4: Alterar o prefixo de um elemento, mantendo o restante intacto (exemplo de caso especial)
$dom = Dom\XMLDocument::createFromString('<prefixo:root xmlns:prefixo="urn:x"/>');
$root = $dom->documentElement;
$root->rename($root->namespaceURI, 'foo:' . $root->localName);
// Prefixo alterado, mas não na serialização devido ao namespace urn:x estar
// vinculado ao "prefixo" pelo atributo.
var_dump($root->prefix); // string(3) "foo"
echo $dom->saveXML(); // <prefixo:root xmlns:prefixo="urn:x"/>
// Corrigimos isso renomeando o atributo ou removendo-o.
$root->removeAttribute('xmlns:prefixo');
echo $dom->saveXML(); // <foo:root xmlns:foo="urn:x"/>
Funções DOM como
Element::insertAdjacentElement(string $where, Element $element)
e
Element::insertAdjacentText(string $where, string $data)
têm um primeiro argumento $where
.
Existem apenas quatro valores válidos para $where
: "beforebegin"
,
"afterbegin"
, "foreend"
, "afterend"
.
Então, na verdade, isso é uma enum disfarçada.
Proponho usar o recurso enum
do PHP.
Isso evitaria erros de programação e tornaria as dicas do IDE muito mais
agradáveis, contribuindo para uma melhor experiência da pessoa desenvolvedora.
Estritamente falando, isso se desvia das especificações do DOM, mas, de qualquer
forma, já modelamos as classes DOM de uma forma que se ajusta ao modelo OOP do
PHP.
Na verdade, eu proporia permitir o uso de enums onde fizer sentido na extensão
para novas APIs.
Como a classe Element
não existia antes da
RFC de conformidade opcional com a especificação DOM,
podemos alterar a assinatura sem afetar os usuários, já que nenhuma versão do
PHP 8.4 foi feita até agora.
Em particular, isso resultará nas seguintes assinaturas de função e enum:
namespace Dom {
enum AdjacentPosition : string {
case BeforeBegin = "beforebegin";
case AfterBegin = "afterbegin";
case BeforeEnd = "beforeend";
case AfterEnd = "afterend";
}
class Element /* ... */ {
public function insertAdjacentElement(AdjacentPosition $where, Element $element): ?Element {}
public function insertAdjacentText(AdjacentPosition $where, string $data): void {}
}
}
A enum AdjacentPosition
é apoiada de forma que os valores literais da
especificação DOM ainda possam ser usados usando
AdjacentPosition::from("beforebegin")
, etc.
Inicialmente, a
RFC de conformidade opcional com a especificação DOM
copiou as APIs existentes das antigas classes DOM sem mudanças para a maioria
das APIs.
Alguém relatou que (DOM)Document::xinclude()
tem um comportamento estranho de
valor de retorno.
Em particular, citando a documentação:
Retorna o número de
XIncludes
no documento, -1 se algum processamento falhou oufalse
se não houve substituições.
Isso parece ser causado por um erro de implementação.
O comportamento mais sensato seria lançar um erro em caso de falha (para evitar
confusão com 0
/false
) e retornar o número de substituições em caso de
sucesso.
Se não houve substituições o número 0 deverá ser retornado.
A nova assinatura desta função ficaria assim:
final class XMLDocument extends Document {
public function xinclude(int $options = 0): int {}
}
A exceção lançada será DOMException
com $code
definido
como DOM_INVALID_MODIFICATION_ERR
.
Nenhum porque esta RFC afeta apenas as classes adicionadas na versão 8.4.
PHP 8.4.
Apenas a ext-dom
é afetada.
Nenhuma ainda.
Tudo fora da ext-dom
.
Inicialmente planejei incluir a propriedade outerHTML
também.
Isso é muito viável com todo o trabalho interno do DOM que aconteceu durante o
ciclo de desenvolvimento do PHP 8.4.
Porém, como não tenho visto demanda por isso, acho que meu tempo será melhor
gasto com outros recursos.
Se alguém realmente quiser isso no PHP 8.4, sinta-se à vontade para fazer uma
implementação de PoC, deve ser bastante viável usando Lexbor e as atuais APIs
internas da ext-dom
.
A classe HTMLElement
pode oferecer algumas propriedades úteis, mas isso foi
deixado de fora porque ninguém realmente solicitou esse recurso até agora, então
o tempo de desenvolvimento é melhor gasto em outro lugar.
Uma votação primária sim/não com maioria de 2/3 para aceitar esta proposta na totalidade.
A votação começou em 10/06/2024 e terminará em 24/06/2024.
Nome | Sim | Não |
---|---|---|
adiel (adiel) | X | |
ashnazg (ashnazg) | X | |
beberlei (beberlei) | X | |
crell (crell) | X | |
devnexen (devnexen) | X | |
galvao (galvao) | X | |
girgias (girgias) | X | |
heiglandreas (heiglandreas) | X | |
jimw (jimw) | X | |
josh (josh) | X | |
kguest (kguest) | X | |
kocsismate (kocsismate) | X | |
levim (levim) | X | |
mauricio (mauricio) | X | |
mbeccati (mbeccati) | X | |
nicolasgrekas (nicolasgrekas) | X | |
nielsdos (nielsdos) | X | |
petk (petk) | X | |
pierrick (pierrick) | X | |
ramsey (ramsey) | X | |
sebastian (sebastian) | X | |
sergey (sergey) | X | |
theodorejb (theodorejb) | X | |
timwolla (timwolla) | X | |
weierophinney (weierophinney) | X | |
Total | 25 | 0 |
- Implementação do seletor CSS
- Implementação de
innerHTML
- Implementação de
TokenList
- Implementação de propriedades de
HTMLDocument
- Implementação de extensões específicas do PHP
Depois que o projeto for implementado, esta seção deverá conter:
- as versões nas quais foi feito o merge
- um link para os commits do git
- um link para a entrada no manual do PHP para o recurso
- um link para a seção de especificação da linguagem (se houver)
- Tratamento de erros de
innerHTML
- Especificação DOM
- Especificação HTML que define adendos ao DOM
- Antiga solicitação do recurso para obter namespaces em escopo
- Solicitação de recurso para
TokenList
- Discussão (externals.io)
- 0.1: Primeira versão colocada em discussão e votação
Gostaria de agradecer a Toon Verwerft por seus comentários e testes iniciais.