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).
Related
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
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
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.
I have a similar code snippet like this
class Search
{
public function search($for, $regEx, $flag) //I would like this to be the constructor
{
// logic here
return $this;
}
}
Then I have another class that creates an object from it, later than tries to use the object.
class MyClass
{
public function start()
{
$this->search = new Search();
}
public function load()
{
$this->search($for, $regEx, $flag);
}
}
My question is, is it possible to create an object first THEN give it the parameters?
I know there are some way around this BUT I only ask because I want to use the object like this
$this->search($params);
// I have my methods chained, so I could use it in one line like
// $this->search($params)->hasResults();
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
The way I have it set up right now, I would need to use it like this
$this->search->search($params);
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
I have a method called search() that does the logic, and I don't want to be redundant in my naming nor do I want to change the name of the method.
I know another way to keep the visual appeal sane I could pass a variable like so
$search = $this->search->search($params);
then
$search->hasResults();
At the same time I am trying to introduce myself to new OOP concepts and learn from them. Would this require passing things by reference? or setting up some type of magic method?
While the previous anwsers show that you can, I wouldn't use it, because it breaks the concept of encapsulation. A proper way to achieve what you want is the following
class Search
{
public function __constructor($for='', $regEx='', $flag='')
{
$this->Setup($for, $regEx, $flag);
}
public function Setup($for, $regEx, $flag)
{
//assign params
//clear last result search
//chain
return $this;
}
public function search()
{
// logic here
return $this;
}
}
In this way, you can reuse the object and have the params in the constructor, without breaking encapsulation.
Yes it is possible
See the below example
<?php
class a{
public $a = 5;
public function __construct($var){
$this->a = $var;
}
}
$delta = new a(10);
echo $delta->a."\n";
$delta->__construct(15);
echo $delta->a."\n";
Output will be:
10 15
Yep, you can.
class Example {
public $any;
function __counstruct($parameters,$some_text) {
$this->any=$some_text;
return $this->any;
}
}
You can call constructor:
$obj = new Example (true,'hello');
echo $obj->any;
$obj->__construct(true,'bye-bye');
echo $obj->any;
I was able to create the visual coding I wanted by using the __call() magic method like this
public function __call($name, $params)
{
$call = ucfirst($name);
$this->$name = new $call($params);
}
from there I could use this
$this->test->search($params);
$this->test->search->hasResults();
I of course now set the search() method to the class constructor
Ive looked and tried but I can't find an answer.
In PHP, is it possible to call a class' member function (when that class requires a constructor to receive parameters) without instantiating it as an object?
A code example (which gives errors):
<?php
class Test {
private $end="";
function __construct($value) {
$this->end=$value;
}
public function alert($value) {
echo $value." ".$this->end;
}
}
//this works:
$example=new Test("world");
$example->alert("hello");
//this does not work:
echo Test("world")::alert("hello");
?>
Unfortunately PHP doesn't have support to do this, but you are a creative and look guy :D
You can use an "factory", sample:
<?php
class Foo
{
private $__aaa = null;
public function __construct($aaa)
{
$this->__aaa = $aaa;
}
public static function factory($aaa)
{
return new Foo($aaa);
}
public function doX()
{
return $this->__aaa * 2;
}
}
Foo::factory(10)->doX(); // outputs 20
Just do this (in PHP >= 5.4):
$t = (new Test("Hello"))->foo("world");
I, too, was looking for a one-liner to accomplish this as part of a single expression for converting dates from one format to another. I like doing this in a single line of code because it is a single logical operation. So, this is a little cryptic, but it lets you instantiate and use a date object within a single line:
$newDateString = ($d = new DateTime('2011-08-30') ? $d->format('F d, Y') : '');
Another way to one-line the conversion of date strings from one format to another is to use a helper function to manage the OO parts of the code:
function convertDate($oldDateString,$newDateFormatString) {
$d = new DateTime($oldDateString);
return $d->format($newDateFormatString);
}
$myNewDate = convertDate($myOldDate,'F d, Y');
I think the object oriented approach is cool and necessary, but it can sometimes be tedious, requiring too many steps to accomplish simple operations.
You can't call an instance-level method without an instance. Your syntax:
echo Test("world")::alert("hello");
doesn't make a lot of sense. Either you're creating an inline instance and discarding it immediately or the alert() method has no implicit this instance.
Assuming:
class Test {
public function __construct($message) {
$this->message = $message;
}
public function foo($message) {
echo "$this->message $message";
}
}
you can do:
$t = new Test("Hello");
$t->foo("world");
but PHP syntax doesn't allow:
new Test("Hello")->foo("world");
which would otherwise be the equivalent. There are a few examples of this in PHP (eg using array indexing on a function return). That's just the way it is.
For this you can do a
https://www.php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php
reflect your class and trigger the new instance without constructor.
Here a sample code:
<?php
class Test {
private $end="";
function __construct($value) {
$this->end=$value;
}
public function alert($value) {
echo $value." ".$this->end;
}
public function end($value) {
$this->end = $value;
return $this; // return Test object so that you can chain to other function method.
}
}
// Solution #1:
// reflect your class.
$reflector = new \ReflectionClass('Test');
// Then create a new instance without Constructor.
// This will ignore the constructor BUT it will create a new instance of class Test.
$say = $reflector->newInstanceWithoutConstructor();
// use end method that will return the Test object, then you can chain the alert()
$say->end('World!')->alert("Hello"); // output: Hello World!
?>
// this does not work:
echo Test("world")::alert("hello");
// works, as you are calling not to an object of the class, but to its namespace
echo Test::alert("hello");