PHP5: orijinal (ana) sınıfından bir nesne üzerinde uzun bir sınıftan bir yöntemi uygulamak

5 Cevap php

Ben XPath sorguları kolaylaştırmak için 2 yöntem (selectNodes ve selectSingleNode) uygulamak için iki yerli PHP5 sınıfları (DOMDocument ve DOMNode) genişletmek için çalışıyorum. Ben oldukça straighforward olacağını düşündüm, ama ben bir cepten acemi sorun olduğunu düşünüyorum bir sorun sıkışmış ediyorum.

class nDOMDocument extends DOMDocument {
    public function selectNodes($xpath){
    $oxpath = new DOMXPath($this);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}

Sonra ben bu yüzden doğrudan bir düğüm bir XPath sorgusu gerçekleştirebilirsiniz aynı yöntemleri uygulamak için DOMNode uzatmak yapmaya çalıştım:

class nDOMNode extends DOMNode {
    public function selectNodes($xpath){
    $oxpath = new DOMXPath($this->ownerDocument,$this);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}

Şimdi ben (keyfi bir XMLDocument üzerinde) aşağıdaki kodu execute:

$xmlDoc = new nDOMDocument;
$xmlDoc->loadXML(...some XML...);
$node1 = $xmlDoc->selectSingleNode("//item[@id=2]");
$node2 = $node1->selectSingleNode("firstname");

The third line works and returns a DOMNode object $node1. However, the fourth line doesn't work because the selectSingleNode method belongs to the nDOMNode class, not DOMNode. So my question: is there a way at some point to "transform" the returned DOMNode object into a nDOMNode object? I feel I'm missing some essential point here and I'd greatly appreciate your help.

(Özür dilerim, bu benim bir soru düzeltmesi olan http://stackoverflow.com/questions/2573820/)

5 Cevap

You can "tell" a DOMDocument via DOMDocument::registerNodeClass() which class it shall use instead of the default classes when instantiating an object for a certain node type. E.g.

$doc->registerNodeClass('DOMElement', 'Foo');

Her zaman dom "normal" örneğini verecek bir DOMElement şimdi bir örneğini oluşturur Foo.

$doc = new nDOMDocument;
$doc->loadxml('<a><b><c>foo</c></b></a>');

$a = $doc->selectSingleNode('//a');
$c = $a->selectSingleNode('//c');

echo 'content: ', $c->textContent;

class nDOMElement extends DOMElement {
  public function selectNodes($xpath){
    $oxpath = new DOMXPath($this->ownerDocument);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}


class nDOMDocument extends DOMDocument {
  public function __construct($version=NULL, $encoding=NULL) {
    parent::__construct($version, $encoding);
    $this->registerNodeClass('DOMElement', 'nDOMElement');
  }

  public function selectNodes($xpath){
    $oxpath = new DOMXPath($this);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}

baskılar content: foo.

Ama sadece set registerNodeClass('DOMNode', 'MyDOMNode') ve MyDOMNode yerine DOMNode devralmak için artık bir DOMElement bekleyemezsiniz. Yani Eğer üzerine yazmak istediğiniz tüm düğüm türlerini kayıt var.

Sen nDOMDocument :: selectSingleNode () bir nDOMNode nesneyi döndürmek için kod gerekiyordu. Bu olabilir dönüştürmesi büyülü yok.

Ben (zor yoldan da olsa) yol boyunca bazı iyi cepten dersler olacak gibi sizin deneye devam gerektiğini söylüyorlar. Bunda yanlış bir şey yok.

Nesne yönelimli yaklaşımın sonuçlarından biri miras bir tek yönlü bir sokak olmasıdır. Bu çocukların yöntemlerin ana farkında yapmak için hiçbir yolu yoktur, olduğunu. Eğer nesneler topluluğu içinde yineleme mümkün olabilir iken Böylece, sadece güvenilir bir üst sınıf yöntemlerini çağırabilirsiniz. PHP bir yöntem zamanında varsa test etmek ve bu yararlı olabilir yolları var ama aynı zamanda çabuk çirkin alabilirsiniz.

Sadece sürümü - Bu uzatmak zaman yerleşik sınıf, uygulama yerleşik sınıf örnekleri ile çalışma asla böylece completely uzatmak gerekiyor demektir. Sizin durumda, üst sınıfın sınıf türü dönmek ebeveynin yöntemlerin tümü geçersiz kılmak için genişletilmiş sınıfları genişletmek gerekir:

public myClass extends foo {
// override all methods that would normally return foo objects so that they
// return myClass objects.
}

Ben yerine onları doğrudan sınıflara göre, sarıcı nesneleri varolan kütüphane dekorasyon burada daha kapalı olacak düşünüyorum. Zaten gördüğünüz gibi, kolayca DOMDocument için yardımcı yöntemler ekler ve sizin Subclassed nesneleri geri dönmek olamaz.

Özellikle, burada sorun DOMXPath::item() bir nDOMNode dönmek bilmiyor değildir.

Eğer aşağıdaki gibi bir şey yapmaya çalıştık, başarısız (birçok özellikleri gibi görünen read only) olur:

class nDOMDocument extends DOMDocument {

    ...

    public function selectSingleNode($xPath) {
        $node = $this->selectNodes($xPath)->item(0);
        $myNode = new nDOMNode;
        $myNode->set_name($node->get_name()); // fail?
        $myNode->set_content($node->get_content());
        // set namespace
        // can you set the owner document? etc

        return $myNode;
    }

}

Eğer nesneyi sarın eğer yerine hızlı __get() kullanarak mevcut DOMNode arabirimi göstermelidir ve __call() magic methods, ve ek işlevler içerir ve kendi dönmeye karar verebilir Orijinal hedefe ulaşmak için / özel sınıflar tamamladı.

Örnek:

class nDOMNode {

    protected $_node;

    public function __construct(DOMNode $node) {
        $this->_node = $node;
    }

    // your methods

}

class nDOMDocument {

    protected $_doc;

    public function __construct(DOMDocument $doc) {
        $this->_doc = $doc;
    }

    ...

    public function selectNodes($xPath){
        $oxPath = new DOMXPath($this->_doc->ownerDocument, $this->_doc);
        return $oxPath->query($xPath);
    }

    public function selectSingleNode($xPath) {
        return new nDOMNode($this->selectNodes($xPath)->item(0));
    }

}

$doc = new nDOMDocument(new DOMDocument);
$doc->loadXML('<xml>');
$node = $doc->selectSingleNode("//item[@id=2]"); // returns nDOMNode

Umarım bu yardımcı olur.

Burada uzun bir yol almak ve sol ve sağ, biraz DOM JavaScript için yaptığı gibi yukarı aşağı nokta işaret özellikleri, yüklemeniz gerekebilir düşünüyorum. Yapısını oluştururken Bunlar mutlaka atanacaktır.