Page 2 of 2
Posted: Tue Jun 19, 2007 8:47 am
by romain.pelissier
Weirdan, my php einstein, thanks a lot again.
Still, few problems. I have made the modifications to make your code works in php 4 but I then come with some issue.
First, it seems that the function is_a() is not know on my server ... I have find on the internet this fix to make the function works. I have put the following code :
Code: Select all
class Condition {
var $_operator;
var $_operand1;
var $_operand2;
var $_operand1Value = null;
var $_operand2Value = null;
var $_context;
function is_a($anObject, $aClass) {
return get_class($anObject) == strtolower($aClass)
or is_subclass_of($anObject, $aClass);
// ...
}
So the is_a() function works now. But PHP still complaining with this error message :
It seems that it does not like the following :
Code: Select all
$this->_operand2Value = $context[$this->_operand2];
I have tried this fix found on the internet
http://wordpress.org/support/rss/topic/119656 but it does not seem to work for me or maybe I don't know how to set it correctly ...
Can you help me with this?
Posted: Tue Jun 19, 2007 9:23 am
by superdezign
Try typecasting $this->_operand2 to an integer as the index of $context. I'm not sure what it does, but it's telling you that it's either not a string or not an integer.
Code: Select all
$this->_operand2Value = $context[(int)$this->_operand2];
See if it works.
Posted: Tue Jun 19, 2007 9:46 am
by romain.pelissier
Again you have the right solution! Now PHP only displays 'Notice'.
But ...
It seems that the condition are not interpreted correcly ... I have the rules :
Code: Select all
$condition = new Condition(new Condition('a', '<', 'b'), 'or', new Condition('a', '==', 'b'));
and
Code: Select all
function test_function($rule)
{
$a=1;
$b=2;
// no more hacks
$rule->setContext(get_defined_vars());
if ($rule->evaluate())
{
var_dump(true);
print "ok";
// ...
}
else {
print "no ok";
}
}
it display 'no ok' so even if the value of $a and $b are correct, the condition should result to a 'true' which does not seems to be the case here ...
Any idea?
Posted: Tue Jun 19, 2007 10:26 am
by superdezign
'a' and 'b' are strings. I think you're after $a and $b. (Maybe)
Edit: Or not. I haven't read the class yet.
Posted: Tue Jun 19, 2007 10:31 am
by romain.pelissier
If I change
Code: Select all
$condition = new Condition(new Condition('a', '<', 'b'), 'or', new Condition('a', '==', 'b'));
to
Code: Select all
$condition = new Condition(new Condition('$a', '<', '$b'), 'or', new Condition('$a', '==', '$b'));
I have got the same result ...
Posted: Tue Jun 19, 2007 4:05 pm
by feyd
Likely, you need to lose the single quotes around $a and $b.
Posted: Tue Jun 19, 2007 6:16 pm
by Weirdan
superdezign wrote:
I think you're after $a and $b. (Maybe)
No.
feyd wrote:
Likely, you need to lose the single quotes around $a and $b.
No.
superdezign wrote:
Code: Select all
$this->_operand2Value = $context[(int)$this->_operand2];
That's wrong. $this->_operand1 and $this->_operand2 supposed to be strings because they hold variable names (or subconditions, but that's handled in another branches of those if statements). Constructor accepts variable names without $ signs because that's how they are returned by get_defined_vars() function.
romain.pelissier, please post your code (Condition class) for us to see if you have converted it properly.
Posted: Tue Jun 19, 2007 6:27 pm
by superdezign
Yeah, that's why I shut up. I read the class and it does stuff I've never tried before.

Posted: Wed Jun 20, 2007 8:07 am
by romain.pelissier
Hi Wierdan, master of the php universe,
Here is the code that I have modified to run in PHP4 including the is_a() function. I have commented the modification that I have made.
Code: Select all
<?
class Condition {
// Removed private and replace with var
var $_operator;
var $_operand1;
var $_operand2;
var $_operand1Value = null;
var $_operand2Value = null;
var $_context;
// The function is_a() was added because without it, PHP gives me some errors,
// This piece of code was found on the internet and on the php.net web site.
function is_a($anObject, $aClass) {
return get_class($anObject) == strtolower($aClass)
or is_subclass_of($anObject, $aClass);
}
function Condition($operand1, $operator, $operand2) //rename from _construct to Condition
{
$this->_operator = $operator;
$this->_operand1 = $operand1;
$this->_operand2 = $operand2;
}
function __toString()
{
// change $var instanceof by the function is_a($var, "Class")
$op1 = $this->is_a(_operand1, "Condition") ? $this->_operand1->__toString() : $this->_operand1;
$op2 = $this->is_a(_operand2, "Condition") ? $this->_operand2->__toString() : $this->_operand2;
return '( ' . $op1 . ' ' . $this->_operator . ' ' . $op2 . ' )';
}
function _resolveOperands($context = false)
{
if (!is_null($this->_operand1Value) || !is_null($this->_operand2Value))
{
return;
}
if (!$context)
{
$context = $this->_context;
}
// change $var instanceof by the function is_a($var, "Class")
if ($this->is_a(_operand1, "Condition"))
{
$this->_operand1->_resolveOperands($context);
$this->_operand1Value = $this->_operand1->evaluate();
}
else
{
//change from $context[(int)$this->_operand1]; to $context[(int)$this->_operand1
$this->_operand1Value = $context[(int)$this->_operand1];
}
// change $var instanceof by the function is_a($var, "Class")
if ($this->is_a(_operand2, "Condition"))
{
$this->_operand2->_resolveOperands($context);
$this->_operand2Value = $this->_operand2->evaluate();
}
else
{
//change from $context[(int)$this->_operand1]; to $context[(int)$this->_operand1
$this->_operand2Value = $context[(int)$this->_operand2];
}
}
function setContext($context)
{
$this->_context = $context;
}
function evaluate()
{
$this->_resolveOperands();
switch ($this->_operator)
{
case '<': return $this->_operand1Value < $this->_operand2Value;
case '>': return $this->_operand1Value > $this->_operand2Value;
case '==': return $this->_operand1Value == $this->_operand2Value;
case '>=': return $this->_operand1Value >= $this->_operand2Value;
case '<=': return $this->_operand1Value <= $this->_operand2Value;
case '!=': return $this->_operand1Value != $this->_operand2Value;
case 'and': return $this->_operand1Value && $this->_operand2Value;
case 'or': return $this->_operand1Value || $this->_operand2Value;
default: trigger_error('Unknown operator', E_USER_WARNING); return false;
}
}
}
$condition = new Condition(new Condition('$a', '<', '$b'), 'or', new Condition('$a', '==', '$b'));
test_function($condition);
//...
function test_function($rule)
{
$a=1;
$b=2;
// no more hacks
$rule->setContext(get_defined_vars());
if ($rule->evaluate())
{
var_dump(true);
print "ok";
// ...
}
else {
print "no ok";
}
}
?>
Thanks again weirdan!
Posted: Wed Jun 20, 2007 1:52 pm
by Weirdan
Fixes are trivial:
- $this->is_a(_operand1, "Condition"). This is wrong. It should be $this->is_a($this->_operand1, "Condition"). Same goes for _operand2 of course.
- new Condition('$a', '<', '$b'). This is wrong as well. Dollar signs shouldn't be used here, so it should be new Condition('a', '<', 'b')
- $this->_operand1Value = $context[(int)$this->_operand1]; and this is terribly wrong. It should be $this->_operand1Value = $context[$this->_operand1];
Posted: Wed Jun 20, 2007 3:45 pm
by romain.pelissier
Wierdan, the php wikipedia man,
Again, your magic has resolve all my issues. What can I say expect that you should be a god in php programming.
Thanks again. I will post tomorrow the code for PHP5 and PHP4 so other users could see and use it.
Tomorrow, I will set this topic as resolve since, I think, the code and methodology provided by weirdan match exactly what I wanted to acheive. But if other users still want to contribute, they are more than welcome.
Thanks to all people that have contributed to help me.
Posted: Fri Jun 22, 2007 3:20 pm
by romain.pelissier
Wierdan, I still have a little question for you if you still watching this topic.
A strange thing happen. I need to do additional tests but I found a possible issue.
Your code works wonderfully but it seems that in certain circumstancies, the condition does not work.
Let me explain. So the code below works :
Code: Select all
$condition = new Condition('a', '>=', 'b');
test_function($condition);
//...
function test_function($rule)
{
$is_date=date("Ymd");
//$debut = intval(substr($fi['datedebut'],0, 6));
//$fin = intval(substr($fi['datefin'], 0, 6));
$dateactu = intval(substr($is_date, 0, 6));
$a=1;
$b=2;
// no more hacks
$rule->setContext(get_defined_vars());
if ($rule->evaluate())
{
var_dump(true);
print "ok";
// ...
}
else {
print "no ok";
}
}
In my case however, I do additional operation in the function, like a foreach loop that retreive the value of a and b from an array. It seems that when you initialise a and b in the same function several time and call the $rule->evaluate() function, the code seems to not be able to see that the variables value change.
If the condition is :
and I have an array of value for a and b like this :
Code: Select all
array[0][start]=1
array[0][end]=0
array[1][start]=2
array[1][end]=5
As you can see, at position [0], condition a > b is true if a=array[0][start] and b=array[0][end] and the condition should be false for [1]
In the code, I dynamically change the value of a and b from my array:
Code: Select all
function test_function($rule)
{
$is_date=date("Ymd");
//$debut = intval(substr($fi['datedebut'],0, 6));
//$fin = intval(substr($fi['datefin'], 0, 6));
$dateactu = intval(substr($is_date, 0, 6));
foreach ($array as $val){
$a=$val['start'];
$b=$val['end'];
// no more hacks
$rule->setContext(get_defined_vars());
if ($rule->evaluate())
{
var_dump(true);
print "ok";
// ...
}
else {
print "no ok";
}
}
}
(Please note that I have not tested yet the code above but I have the quite same structure in another code and this does not work for me, it is just to give you an idea. I will test THIS code as soon as I can to be sure.)
So, first 'ok' should be displayed and then 'no ok'. But for me, I still have some 'ok' ...
I am not really sure but it seems that PHP does not seems to see that the value for a and b have changed ...
An idea ?
Posted: Sat Jun 23, 2007 4:29 am
by Weirdan
it could be because of this safeguard:
Code: Select all
if (!is_null($this->_operand1Value) || !is_null($this->_operand2Value))
{
return;
}
During subsequent invocations operand values are already resolved, so it's not picking up new ones.
Posted: Sun Jun 24, 2007 1:29 pm
by Weirdan
ok, fixed those problems:
Code: Select all
class Condition {
var $_operator;
var $_operand1;
var $_operand2;
var $_operand1Value = null;
var $_operand2Value = null;
function is_a($anObject, $aClass) {
return
is_object($anObject)
and (
strtolower(get_class($anObject)) == strtolower($aClass)
or is_subclass_of($anObject, $aClass)
);
}
function Condition($operand1, $operator, $operand2)
{
$this->_operator = $operator;
$this->_operand1 = $operand1;
$this->_operand2 = $operand2;
}
function __toString()
{
$op1 = $this->is_a($this->_operand1, "Condition") ? $this->_operand1->__toString() : $this->_operand1;
$op2 = $this->is_a($this->_operand2, "Condition") ? $this->_operand2->__toString() : $this->_operand2;
return '( ' . $op1 . ' ' . $this->_operator . ' ' . $op2 . ' )';
}
function _resolveOperands($context)
{
if ($this->is_a($this->_operand1, "Condition")) {
$this->_operand1Value = $this->_operand1->evaluate($context);
} else {
$this->_operand1Value = $context[$this->_operand1];
}
if ($this->is_a($this->_operand2, "Condition")) {
$this->_operand2Value = $this->_operand2->evaluate($context);
} else {
$this->_operand2Value = $context[$this->_operand2];
}
}
function evaluate($context)
{
$this->_resolveOperands($context);
switch ($this->_operator)
{
case '<': return $this->_operand1Value < $this->_operand2Value;
case '>': return $this->_operand1Value > $this->_operand2Value;
case '==': return $this->_operand1Value == $this->_operand2Value;
case '>=': return $this->_operand1Value >= $this->_operand2Value;
case '<=': return $this->_operand1Value <= $this->_operand2Value;
case '!=': return $this->_operand1Value != $this->_operand2Value;
case 'and': return $this->_operand1Value && $this->_operand2Value;
case 'or': return $this->_operand1Value || $this->_operand2Value;
default: trigger_error('Unknown operator', E_USER_WARNING); return false;
}
}
}
$condition = new Condition(new Condition('a', '<', 'b'), 'or', new Condition('a', '==', 'b'));
echo $condition->__toString() . "\n";
test_function($condition);
//...
function test_function($rule)
{
$array = array(
array('a' => 1, 'b' => 2),
array('a' => 2, 'b' => 1),
);
foreach ($array as $element) {
$a = $element['a'];
$b = $element['b'];
if ($rule->evaluate(get_defined_vars())) {
var_dump(true);
} else {
var_dump(false);
}
}
}
Posted: Tue Jun 26, 2007 1:38 pm
by romain.pelissier
Weirdan, you should have some php code in your genes
It works this time.
I will post soon the code for PHP5 and PHP4 for those who are interested.
Thanks again.