Referencing to DOMDocument method from DOMElement - php

I have written below classes to make certain DOM operations easier. I want the Easy_Dom_Element's functions to be able to accept both a string and an element as input though. To do that I have to access DOMDocument's createElement method. The call to Easy_Dom::toElement works fine, but $this within that method points to the Easy_Dom_Element instead of Easy_Dom itself. I've tried a static call to createElement like so: Easy_Dom::createElement($element) but for some reason that is not allowed.
class Easy_Dom extends DOMDocument{
/*function __construct(){
$this->registerNodeClass('DOMElement', 'Easy_Dom_Element');
}*/
//Gets the first element by tag name
function getElement($tagName){
return $this->getElementsByTagName($tagName)->item(0);
}
//Creates DOMElement from string if needed
function toElement($element){
if(is_string($element))$element = $this->createElement($element);
return $element;
}
}
class Easy_Dom_Element extends DOMElement{
function prependChildEl($element){
$element = Easy_Dom::toElement($element);
$this->insertBefore($element, $this->firstChild);
return $element;
}
function appendChildEl($element){
$element = Easy_Dom::toElement($element);
$this->appendChild($element);
return $element;
}
}
$_testxml = new Easy_Dom('1.0', 'ISO-8859-1');
$_testxml->registerNodeClass('DOMElement', 'Easy_Dom_Element');
//load defaults
$_testxml->load('default.xml');
//test above classes
$test = $_testxml->getElement('general_title');
$test->appendChildEl('test');
echo $test->nodeValue;
echo $_testxml->saveXML();

Just when I was about to give up on this I finally figured it out, it turns out the answer was really simple.
Just reference the DOMElement's DOMDocument using the ownerDocument property like this:
$DOMDocumentFunctionResult = $this->ownerDocument->DOMDocumentFunction();
So in my example:
class Easy_Dom extends DOMDocument{
/*function __construct(){
$this->registerNodeClass('DOMElement', 'Easy_Dom_Element');
}*/
//Gets the first element by tag name
function getElement($tagName){
return $this->getElementsByTagName($tagName)->item(0);
}
//Creates DOMElement from string if needed
function toElement($element){
if(is_string($element))$element = $this->createElement($element);
return $element;
}
}
class Easy_Dom_Element extends DOMElement{
function prependChildEl($element){
$element = $this->ownerDocument->toElement($element);
$this->insertBefore($element, $this->firstChild);
return $element;
}
function appendChildEl($element){
$element = $this->ownerDocument->toElement($element);
$this->appendChild($element);
return $element;
}
}

What version of PHP are you using?
< PHP 5.3 doesn't allow calling of static methods of inherited classes.
See : http://uk3.php.net/lsb

Related

Objects field in callback function PHP

I'm creating a class to manage user submitted articles. Within this class, I'm also using the PHP Simple Dom Parser class. This class allows you to apply a callback function when it outputs HTML, which I use to filter out unwanted elements. Outside of a class, in procedural style, it's implemented by doing this:
<?php
$html = file_get_html($_FILES["repfile"]["tmp_name"]);
function fileFilter($element){
$toDelete = array("img", "script", "object", "iframe");
foreach($toDelete as $el){
if($element->tag==$el){
$element->outertext = "";
}
}
}
$html->set_callback("fileFilter");
$finalContent = (string)$html->find("div", 0)->innertext;
?>
Now what I want to do in my class is something along the lines of
<?php
class Article{
public $blockedElements;
public $html;
function __toString(){
$html->set_callback("Article::htmlFilter");
return (string)$html;
}
public static function htmlFilter($element){
foreach($this->blockedElements as $el){
if($element->tag==$el){
$element->outertext = "";
}
}
}
}
?>
The obvious problem is that you can't use the $this->blockedElements in a static method, so how would I be able to implement this?
By not making htmlFilter static.
Assuming you got an Article instance, you can pass the instance as a callback as well:
function __toString(){
$html->set_callback(array($this, "htmlFilter"));
return (string)$html;
}
If you do that, then htmlFilter will also be called as an instance method (provided you remove the static keyword).

Converting xml DOMDocument to HTML string and echo

I have this Class
Class Parser extends DOMDocument {
public function setHTML($file) {
$this->loadHTMLFile($file);
}
public function setAttribute($name, $value) {
return $this->setAttribute($name, $value);
}
public function findById($id) {
return $this->getElementById($id);
}
}
and I use it like this:
$parser = new Parser();
$parser->setHTML('as.html');
$parser->findById("xaxa")->setAttribute('name1', 'value1');
but if I have to see the changed HTML I call SAVEHTML like this
echo $parser->saveHTML();
Is there a way to make it automatic? Like when method setAttribute is called to make
$this->saveHTML()
auto so I will have this
$html =$parser->findById("xaxa")->setAttribute('name1', 'value1');
then call
echo $html;
Thanks alot
Well, the DOM object cannot be used (directly) as string, and when you'll try for example echo it will throw an exception
Catchable fatal error: Object of class DOMDocument could not be converted to string in ...
The saveHTML method is explicitly designed to return the nodes as HTML string - than you can echo it. Bear in mind, that actually the nodes are already updated (saved!) after you call the setAttribute method - the saveHTML is just for rendering a html string from the nodes.
Providing I understand your concept, and you still think you want it your way, maybe you can try the below solution - but just for the record, I didnt test the code.
Class Parser extends DOMDocument
{
public function setHTML($file)
{
$this->loadHTMLFile($file);
}
public function setAttribute($name, $value)
{
return $this->setAttribute($name, $value);
}
public function findById($id)
{
return $this->getElementById($id);
}
public function __toString()
{
return $this->saveHTML();
}
}
// and now this should work
$parser = new Parser();
$parser->setHTML('as.html');
$parser->findById("xaxa")->setAttribute('name1', 'value1');
echo $parser;

Convert static method to lambda in PHP

I want to get static method from class and copy it to variable.
This is non-working example illustrating my question:
class foo
{
public static function bar($argument){ return 2*$argument; }
}
$class = new ReflectionClass('foo');
// here is no ReflectionMethod::getClosure() method in reality
$lambda = $class->getMethod('bar')->getClosure();
echo $lambda(3);
So my question: is this possible by any normal way? I find only one way for now. I can parse source file, get method source from it and convert it using create_function() but it's too perverse.
Just wrap it with closure.
$lamda = function($argument){return foo::bar($argument);};
Or you can try to use something like this
function staticMethodToClosure($class, $method) {
return function($argument)use($class, $method){return $class::$method($argument);};
}
An array in the format array($className, $methodName) is invokable as a static method call so this may work for you.
class foo
{
public static function bar($argument){ return 2*$argument; }
public static function getStaticFunction($arg){
return array("foo", $arg);
}
}
$a = foo::getStaticFunction("bar");
echo $a(5); // echos 10

php class and arrays madness at least for me

So there are two things that I am stuck on now. First
class DisplayTaxonomy {
public $MyArray[]= new DisplayTaxonomy(); //the compiler says syntax error
//things I have tried
//public $ss[]= new Object();
}
Second! in a function like this:
public function whatever()
{
$Temp = new DisplayTaxonomy();
$Temp->setADTitle("1");
$MyArray[]= $Temp;//works just fine.
//then i tried to return the array
return $MyArray[];
}
I get the following
//Cannot use [] for reading in C:\xampp\htdocs\wordpress\wp-//content\themes\twentyeleven\page.php on line 52
then in the client side
$y=new DisplayTaxonomy();
$myArray[]=new DisplayTaxonomy();//works fine dont know why I cant do this in theclass.
$myArray[]=$y->getArrayOfDisplayTaxonomyObjects();
echo $myArray[0]->getADTitle();
It seems you want to create a class that handles a collection of Taxonomy objects. In that case you should have two classes, instead of making a class store instances of itself.
class TaxonomyContainer
{
private $collection = array();
public function addElement(DisplayTaxonomy $element)
{
$this->collection[] = $element;
}
public function getElements()
{
return $this->collection;
}
}
class DisplayTaxonomy
{
private $adTitle;
public function setAdTitle($adTitle)
{
$this->adTitle = $adTitle;
}
//and other functionality the Taxonomy object should have
}
Then you can avoid the ugly self replicating behaviour and separate your concerns.
$container = new TaxonomyContainer();
$element = new DisplayTaxonomy();
$container->addElement($element);
On the next level, it might be worth considering the use of one of PHP's predefined interfaces for the Container class.
You declare objects in the function body and initiate them in the constructor (or a member function). You don't use [] when returning an array, $array[] has the same functionality as array_push, nothing more.
To clarify,
class myClass {
public $obj = array();
public function __construct() {
$this->obj[] = new OtherObject();
}
public function getObj() {
return $this->obj;
}
}
You cannot do this :
class DisplayTaxonomy {
public $MyArray[]= new DisplayTaxonomy();
}
because it's like an infinite loop :) So you have to use __contruct() function.
After change the :
return $MyArray[];
to :
return $MyArray;
Your first issue is due to trying to call the class you're declaring.
class DisplayTaxonomy {
public $MyArray[]= new DisplayTaxonomy();
You should initialize your object outside of the class, in the portion of code that you need to reference the class.
In addition, the object is already an array so you can omit attaching [] to the end return $MyArray:
public function whatever(){
$Temp = new DisplayTaxonomy();
$Temp->setADTitle("1");
$MyArray[] = $Temp;
return $MyArray;
}
You're declaring the array object here:
$MyArray[]= $Temp;//works just fine
You can't call code (new DisplayTaxonomy()) when definining class properties. You'll have to assign the value in the constructor of the class:
class Foo
{
public $MyArray;
public function __construct()
{
$this->MyArray = new DisplayTaxonomy();
}
}
The other issue is that the $array[] shortcut is for appending to an array. If you want to just return the array (and not write to the array which you're asking about with []), simply skip []:
return $MyArray;
Expanded:
As Vincent Joigƞie pointed out below; you're trying to create a class with the same name as the class you're already creating. This doesn't make any sense, except for static properties. In that case you can't use __construct(), but would rather create / set the object in the static method you're calling to retrieve the object the first time:
static public function getInstance()
{
if (self::$MyArray === null)
{
self::$MyArray = new DisplayTaxonomy();
}
return self::$MyArray;
}
This is however probably not what you want, and it seems you've confused something in your logic in your class definition. Guessing freely you might just want:
class Foo
{
public $MyArray = array();
}
As array() is a static assignment (and not a function call), it's allowed in the class definition.

Returning SimpleXML object in class constructor - why does it not work?

Hey, I have a small test case set up as following:
class T {
public function __construct(){
$obj = new SimpleXMLElement(file_get_contents('vote.xml'));
return $obj;
}
}
$vv=new T;
var_dump($vv);
The dump of $vv equals, in this case, object(T)#1 (0) { } - in other words, not the expected output
When I return the object in a separate function, though, like this:
class T {
public function stackOverflow(){
$obj = new SimpleXMLElement(file_get_contents('vote.xml')); // or simplexml_load_file
return $obj;
}
}
$vv=new T;
$vv = $vv->stackOverflow();
var_dump($vv);
output is as expected (the object containing contents of 'vote.xml', tags and attributes). Why can I not return the object inside of the constructor? Thanks!
The constructor will only ever return a reference to the newly created object. This is intentional -- how else would you get a reference to the new object?
You could, however, create an object property in your constructor and then access it from outside. This would mean that you would create the object during the constructor process, so it would be done at the right time and, what's more, could be guaranteed to be done.
class T {
public $sxml;
public function __construct(){
$this->sxml = new SimpleXMLElement(file_get_contents('vote.xml'));
}
}
$vv=new T;
var_dump($vv->sxml);
Of course, if you don't need the reference to the new object, you could use a static method instead and never use the constructor:
class T {
public static function sxml() {
return new SimpleXMLElement(file_get_contents('vote.xml'));
}
}

Categories