My host suddenly changed something , and now my sites ( most wp - around 100 ) are getting the infamous error Invalid opcode 153/1/8
The line(s) responsible for it :
$f = function() use ($out) {
echo $out;
};
After 2 minutes of research it appears that the culprit is eAccelerator , which does not support anonymous functions
Both the following questions blamed the error on eAccelerator as well :
Invalide OpCode and php sort function,
https://stackoverflow.com/a/12085901/1244126
Fun fact : the same code was already before a subject of my own 2 questions here on SE and here , where I encountered a problem while using
anonymous functions with older PHP versions ( < 5.3 ) with create_function
$f = create_function(' $out ',' global $out; echo $out;');
So, my question is : how can I change my code in a manner that will avoid the eAccelerator bug AND will work on all php versions . ( it is unlikely that I can convince my host to change something on it´s side )
EDIT I :
For sake of clarity ( although might be slightly irrelevant - the the question is how to have a cross-compatible anonymous functions ) - I am posting the whole relevant code ...
if ( count( $content_widget ) > 0 ) { // avoid error when no widget...
$i=0;
foreach ( $content_widget as $wid ){
$out = null;
$i++;
$widg_id = 'o99_dashboard_widget_dyn_' . $i;
$widg_name = 'widget name - ' . $i;
$out = $wid;
// $f = create_function('$out','global $out;echo $out;');
// $f = create_function('', 'global $out; echo $out ;');
$f = function() use ($out) {
echo $out;
};
// function() use ($out) // NOPE
// $f = $f($out); // NOPE again
wp_add_dashboard_widget($widg_id, $widg_name, $f);
// $i++;
}
}
It is just a simple code to dynamically create dashboard widgets in wp admin area..
It seems that they are using call_user_func
So, you could create new object and pass callable array.
class s {
private $_out = null;
public function __construct($out){
$this->_out = $out;
}
public function a(){
echo $this->_out;
}
}
$function = array(new S('my out'), 'a');
var_dump(is_callable($function));
call_user_func($function);
Related
I'm running into an "Cannot redeclare" error and I can't figure out how to fix it. So I have a few functions in a php file located below. Now these functions iterate over an array of data.
I think I've surmised that the problem is that I'm looping the function over and over again in the foreach loop, and its the foreach loop thats been the problem. It seems like its already writing one the function to memory the first time and then for some reason it doesn't like being evoked again.
Your help appreciated.
P.S I've seen a number of similar posts on the issue such as Fatal error: Cannot redeclare but that doesn't seem to work.
<?php
// *****Code Omitted from Stack****
function postHelper($data, $field1, $field2)
{ //TODO Abstract and make sure post Helper and modify Post can be the same thing.
$result = array();
for ($j = 0; $j < count($data); ++$j) { //iterator over array
if ($field2 == "") {
$result[$j] = $data[$j][$field1];
} else {
return $result[$j] = $data[$j][$field1][$field2];
}
}
return $result;
}
//returns an array with only # and # values
function modifyPost($data)
{
//puts symbol # before read data
function addSymbol($data, $field1, $field2)
{
$info = postHelper($data, $field1, $field2);
foreach ($info as &$n) {
$n = '#' . $n;
}
print_r($info);
}
/*
Parse texts and returns an array with only # or # signs used
*/
function parseText($data)
{
$newarr = array();
$text = postHelper($data, "text", "");
foreach ($text as &$s) { //separates into words
$ex = explode(" ", $s);
foreach ($ex as &$n) { //if text doesnt' begin with '#' or '#' then throw it out.
if (substr($n, 0, 1) === '#' || strpos($n, '#') !== false) {
array_push($newarr, $n . ',');
}
}
}
return $newarr;
}
}
foreach ($posts as $entry) {
if (!function_exists('modifyPost')) {
$nval = "hello";
modifyPost($entry);
$entry['mod_post'] = $nval;
}
}
?>
EDIT: I've solved the error. Turns out that the original posts did actually work. I messed in naming. I will give points to anyone who can explain to me why this is necessary for a call. Moreover, I will update post if there is an additional questions that I have.
Php doesn't support nested functions. Although you technically can declare a function within a function:
function modifyPost($data)
{
function addSymbol($data, $field1, $field2)
the inner function becomes global, and the second attempt to declare it (by calling the outer function once again) will fail.
This behaviour seems counter-intuitive, but this is how it works at the moment. There's RFC about real nested functions, which also lists several workarounds for the problem.
The error says it all. You have duplicate modifyData() & parseText functions.
Remove the top half of the php file so only one of each occurs.
First time I am trying to use the dynamic create_function, and up to now, not much success :-)
My function is this :
function o99_brsa_custom_widgets() {
global $wp_meta_boxes;
global $o99_brsa_options;
for($i=0; $i> count($o99_brsa_options[content]); $i++) {
$widgt_id = 'o99_dashboard_widget_dyn' . $i;
$widgt_name = 'obmek99 widget name' . $i;
$out = $o99_brsa_options[content][$i];
$f = create_function(' $out ',' global $out; echo $out;');
do_the_widgets($widgt_id, $widgt_name, $f);
}
}
The do_the_widgets() action is accepting only a direct echo and prints the content of the widget.
The $o99_brsa_options[content] is a verified array with $i elements (each is content) .
The strange thing is that the $i is working on the $widgt_id and $widgt_name but on the create_function() I get the same value printed in all widgets . ( echo $out )
It seems that I do not know how to pass a simple variable to the new function ( I am using global inside create_function(), but it helps little as for now .
So, what is my mistake / misunderstanding / misuse now :-) ??
create_function was during the stone age , when kaᵠ used pen and paper to write applications, when PeeHaa埽 got a beer because he wrote hello would, The world is better now please use closures
$f = function ($out) {
echo $out;
};
$f("Welcome");
You would thank me one day, But you can only use create_function if you are Gordon (The machine from the past sent here to torment us) he wrote this
$fn = create_function(
'$x',
'return $x; } $foo = 42; function foo($int) { return $int; '
);
See Live Demo
Alright I'm working with a large multidimensional array which has more information in it than I need and I want to loop through it to filter the data which I'm interested in. Sadly this multidimensional array is produced dynamically and doesn't always contain the data I want, so I have to use logic like:
if(isset($ar['b']['ba']['baa'])){
echo '<h3>'.$ar['b']['ba']['baa'].'</h3>';
}
if(isset($ar['b']['ba']['baba'])){
echo '<h3>'.$ar['b']['ba']['baba'].'</h3>';
}
if(isset($ar['b']['ba']['babb'])){
echo '<h3>'.$ar['b']['ba']['babb'].'</h3>';
}
The above works great but its a bit messy-looking so I converted the above to:
$refAr=array();
$refAr[]='b->ba->baa';//3
$refAr[]='b->ba->bab->baba';//4
$refAr[]='b->ba->bab->babb';//5
The above looks a lot more nice and neat and is how I want to control the script in case I need to reference different keys in the future. The problem I am having is trying to use the above format to actually reference the array. I thought variable variables would work but apparently it fails. My second attempt using eval worked but I'm not very happy with my solution. This is where I need you guys to come in, is there a better way to do this? Here's my attempt below:
<?php
$ar=array(
'a'=>array('aa'=>1,'ab'=>2),
'b'=>array(
'ba'=>array('baa'=>3,'bab'=>array('baba'=>4,'babb'=>5),'bac'=>array('baca'=>6,'bacb'=>7)),
)
);
$refAr=array();
$refAr[]='b->ba->baa';//3
$refAr[]='b->ba->bab->baba';//4
$refAr[]='b->ba->bab->babb';//5
foreach($refAr as $ref)
{
$r=explode('->',$ref);
$r="\$ar['".implode("']['",$r)."']";
echo '<h1>'.$r.'</h1>';
echo '<h3>'.$$r.'</h3>';//undefined
eval('$t='.$r.';');
echo "<h3>$t</h3>";//works but uses eval, is there a better way?
}
You can try
$ar = array();
$ar['b']['ba']['baa'] = 3;
$ar['b']['ba']['bab']['baba'] = 4;
$ar['b']['ba']['bab']['babb'] = 5;
$refAr = array();
$refAr[] = 'b->ba->baa'; // 3
$refAr[] = 'b->ba->bab->baba'; // 4
$refAr[] = 'b->ba->bab->babb'; // 5
foreach ( $refAr as $ref ) {
$t = $ar;
foreach ( explode("->", $ref) as $v ) {
if (!isset($t[$v]))
break;
$t = $t[$v];
}
is_array($t) and $t = null;
echo "<h3>$t</h3>";
}
Output
345
I decided to answer my own question. This is what I wound up using:
<?php
//Sample PHP representation of dynamically-pulled JSON data from an untrusted source
$ar=array(
'a'=>array('aa'=>1,'ab'=>2),
'b'=>array(
'ba'=>array('baa'=>3,'bab'=>array('baba'=>4,'babb'=>5),'bac'=>array('baca'=>6,'bacb'=>7)),
)
);
//Reusable function
function resolveReference($ar,&$ref)
{
$t = $ar;
foreach ( explode('->',$ref) as $v )
{
if (!array_key_exists($v,$t)){$ref=null;return false;}
$t = $t[$v];
}
$ref=$t;
return true;
}
//The references I'm interested in but don't know if my dynamic data will contain these keys every time
$refAr=array();
$refAr[]='b->ba->baa';
$refAr[]='b->ba->bab->baba';
$refAr[]='b->ba->bab->babb';
$refAr[]='b->doesnt->exist';
foreach($refAr as $ref)
{
echo '<h1>'.$ref.'</h1>';
if(resolveReference($ar,$ref))
{
echo '<h3><span style="color:blue;">'.$ref.'</span></h3>';
}else{
echo '<h3><span style="color:red;">Alternative text for non-existent expected reference</span></h3>';
}
}
So, I've written some rather convoluted 'functional' PHP code to perform folding on an array. Don't worry, I won't use it anywhere. The problem is, PHP's 'each' function only seems to go as far as the end of an array as it is statically (actually, see bottom) declared.
// declare some arrays to fold with
$six = array("_1_","_2_","_3_","_4_","_5_","_6_");
// note: $ns = range(0,100) won't work at all--lazy evaluation?
$ns = array(1,2,3,4,5,6,7,8);
$ns[8] = 9; // this item is included
// add ten more elements to $ns. each can't find these
for($i=0; $i<10; ++$i)
$ns[] = $i;
// create a copy to see if it fixes 'each' problem
$ms = $ns;
$ms[0] = 3; // Just making sure it's actually a copy
$f = function( $a, $b ) { return $a . $b; };
$pls = function( $a, $b ) { return $a + $b; };
function fold_tr( &$a, $f )
{
$g = function ( $accum, &$a, $f ) use (&$g)
{
list($dummy,$n) = each($a);
if($n)
{
return $g($f($accum,$n),$a,$f);
}
else
{
return $accum;
}
};
reset($a);
return $g( NULL, $a, $f );
}
echo "<p>".fold_tr( $six, $f )."</p>"; // as expected: _1__2__3__4__5__6_
echo "<p>".fold_tr( $ns, $pls )."</p>"; // 45 = sum(1..9)
echo "<p>".fold_tr( $ms, $pls )."</p>"; // 47 = 3 + sum(2..9)
I honestly have no clue how each maintains its state; it seems vestigial at best, since there are better (non-magical) mechanisms in the language for iterating through a list, but does anyone know why it would register items added to an array using $a[$index] = value but not '$a[] = value`? Thanks in advance any insight on this behavior.
Your loop is exiting early thanks to PHP's weak typing:
if($n)
{
return $g($f($accum,$n),$a,$f);
}
else
{
return $accum;
}
when $n is 0 (e.g. $ns[9]), the condition will fail and your loop will terminate. Fix with the following:
if($n !== null)
I would love to know if this script is good to know the execution of php script ?
for miliseconds
<?php
$timestart = microtime(true);
/* Blah Blah here ... */
$timeend = microtime(true);
echo 'Execution Time : '.round((timeend - timestart) * 1000, 2);
?>
I have no ideas about using OOP (object-oriented programming) with it.
Also I'll make a script who will parse a text files (.txt), I'll have maybe 120 - 700 lines, which way is better to know the data treatment ?
Does the time depend on number of lines?
I use this Timer class i wrote some time ago. An advantage is that it's "incremental" you can start a timer inside a loop, and it will append the time between start and stop.
Please note that if you do that, it will had quite some time to execution.
basic usage:
$myTimer = new Timer();
$myTimer->start('hello'); // $myTimer = new Timer('hello'); is a shorthand for this.
for ($i=0; $i<100000; $i++)
{
$myTimer->start('slow suspect 1');
// stuff
$myTimer->stop('slow suspect 1');
$myTimer->start('slow suspect 2');
// moar stuff
$myTimer->stop('slow suspect 2');
}
$myTimer->stop('hello');
$myTimer->print_all();
please note it's limited and far not the fastest way to do it. creating and destoying classes takes time. When done inside "logical" loops, it can add quite some time. but to trace some complex program with multiple imbricated loops, or recursive functions calls, this stuff is precious
<?php
class Timer_
{
public $start;
public $stop;
public function __construct()
{
$this->start = microtime(true);
}
}
class Timer
{
private $timers = array();
public function __construct($firsTimer=null)
{
if ( $firsTimer != null) $this->timers[$firsTimer][] = new Timer_();
}
public function start($name)
{
$this->timers[$name][] = new Timer_();
}
public function stop($name)
{
$pos = count($this->timers[$name]) -1 ;
$this->timers[$name][$pos]->stop = microtime(true);
}
public function print_all($html=true)
{
if ( $html ) echo '<pre>';
foreach ($this->timers as $name => $timerArray)
{
$this->print_($name, $html);
}
if ( $html ) echo '</pre>';
}
public function print_($name, $html=true)
{
$nl = ( $html ) ? '<br>' : NEWLINE;
$timerTotal = 0;
foreach ($this->timers[$name] as $key => $timer)
{
if ( $timer->stop != null )
{
$timerTotal += $timer->stop - $timer->start;
}
}
echo $name, ': ', $timerTotal, $nl;
}
}
?>
If you want to do it in a OO manner, you can have a class, where you start.
$timer->start('piece1');
//code1
$timer->stop('piece1');
echo 'Script piece1 took '.$timer->get('piece1').' ms';
I believe it is done like that in codeigniter framework.
The point of these names ('piece1') is that you can have multiple timers running at the same time (example one in another). The code for implementihg is fairly simple, about 10 lines.