Is it somehow possible to "glue" two reference variables?
For example
$more = &$first.':'.&$second;
Using this, i receive a syntax error, an unexpected &.
Full code
$numOf = isset($_GET['numof']) ? $_GET['numof'] : 'x';
if($numOf == 1) {
$more = &$first;
} else if($numOf == 2) {
$more = &$first.':'.&$second;
} else {
$more = '';
}
$results = array(); // array with results from database
foreach($results as $res) {
$first = $res[0];
$second = $res[1];
echo $more.$res[3];
}
You should use a Closure to achieve what you want. Indeed, you need PHP 7(Maybe 5.6, can't tell as I can't test) in order to achieve desired result. Here's an example:
<?php
$first = "a";
$second = "b";
$more = function(){ global $first,$second; return $first.$second; };
echo $more()."<br>"; // This will output ab
$first = "b";
echo $more(); // This will output bb
One thing you can do is the following :
$ar = array(&$first, &$second);
$more = implode(":", $ar);
not directly, at least not that i know of.
what you could do is create a class with a method that automatically combines the values. if you only want string output, you can use the magic method __tostring, so you can use the class directly:
class combiner
{
private $a;
private $b;
public function __construct(&$a, &$b)
{
$this->a = &$a;
$this->b = &$b;
}
public function __tostring() {
return $this->a.":".$this->b;
}
}
$ta = "A";
$tb = "B";
$combined = new combiner($ta, $tb);
echo $combined; //A:B
$ta = "C";
echo $combined; //C:B
You can get your required result by:
<?php
function more($first, $second){
if(!empty($_GET['numof'])){
if($_GET['numof']==1)
return $first;
elseif($_GET['numof']==2)
return $first.':'.$second
}
return '';
}
$results = array(); // array with results from database
foreach($results as $res) {
$first = $res[0];
$second = $res[1];
echo more($first, $second).$res[3];
}
Related
$printArr = recursive($newArray); //calls recursive function
$data = [];
var_dump($data);
var_dump($printArr);
function recursive($array, $level = 0)
{
$searchingValue = 'tableName';
foreach($array as $key => $value)
{
//If $value is an array.
if(is_array($value))
{
recursive($value, $level + 1);
}
else
{
//It is not an array, so print it out.
if($key == $searchingValue)
{
echo "[".$key . "] => " . $value, '<br>';
$data[] = $value;
}
}
}
}
So I have this function and I am trying to save $value value into $data[] array. But it always returns it empty and I don't know why I can't get $value saved outside the function.
If i echo $value I get what i need but like I've mentioned the variables doesn't get saved in this case - table names.
You need to pass the $data to your recursive function. Also you need to return the $data.
Try this code :
function recursive($array, $level = 0, $data =[])
{
$searchingValue = 'tableName';
foreach($array as $key => $value)
{
//If $value is an array.
if(is_array($value))
{
recursive($value, $level + 1 , $data);
}
else
{
//It is not an array, so print it out.
if($key == $searchingValue)
{
echo "[".$key . "] => " . $value, '<br>';
$data[] = $value;
}
}
}
return $data;
}
You can't access variable $data, which is outside the function, from the function. You need to pass it by reference or return it. Small example
<?php
$a = 1;
// Your case
function b() {
$a = 4;
return true;
}
// Passing by reference
function c(&$d) {
$d = 5;
return true;
}
// Using return
function d($d) {
$d = 6;
return $d;
}
b();
var_dump($a);
c($a);
var_dump($a);
$a = d($a);
var_dump($a);
https://3v4l.org/UXFdR
class a {
public $a = "3";
public $b = "0";
public $b = "3";
public $c = "0";
public $d = "0";
public $e = "0";
public $g = "0";
}
How can I find out which properties are greater than zero?
You can use the get_class_vars function outside the object itself like that:
$a = new a();
$class_vars = get_class_vars(get_class($a));
foreach ($class_vars as $name => $value) {
if ($value > 0) {
echo "$name : $value\n";
}
}
put this method inside your class and it will return all vars in array:
public function test() {
$vars = get_object_vars($this);
$r = array();
foreach($vars as $k => $v) {
if($v > 0){ $r[$k] = $v; }
}
return $r;
}
Is it possible to do something like this in PHP?
$index1 = "[0][1][2]";
$index2 = "['cat']['cow']['dog']";
// I want this to be $myArray[0][1][2]
$myArray{$index1} = 'stuff';
// I want this to be $myArray['cat']['cow']['dog']
$myArray{$index2} = 'morestuff';
I've searched for a solution, but I don't think I know the keywords involved in figuring this out.
eval('$myArray[0][1][2] = "stuff";');
eval('$myArray'.$index1.' = "stuff";');
But be careful when using eval and user input as it is vulnerable to code injection attacks.
Not directly. $myArray[$index] would evaluate to $myArray['[0][1][2]']. You would probably have to separate each dimension or write a little function to interpret the string:
function strIndexArray($arr, $indices, $offset = 0) {
$lb = strpos($indices, '[', $offset);
if ($lb === -1) {
return $arr[$indices];
}
else {
$rb = strpos($indices,']', $lb);
$index = substr($indices, $lb, $rb - $lb);
return strIndexArray($arr[$index], substr($indices, $rb+1));
}
}
You can probably find some regular expression to more easily extract the indices which would lead to something like:
$indices = /*regex*/;
$value = '';
foreach($indices as $index) {
$value = $array[$index];
}
To set a value in the array the following function could be used:
function setValue(&$arr, $indices, $value) {
$lb = strpos($indices, '[');
if ($lb === -1) {
$arr = $value;
}
else {
$rb = strpos($indices, ']', $lb);
$index = substr($indices, $lb, $rb);
setValue($arr[$index], substr($indices, $lb, $rb+1), $value);
}
}
Note: I made above code in the answer editor so it may contain a typo or two ; )
$index1 = "[0][1][2]";
$index2 = "['cat']['cow']['dog']";
function myArrayFunc(&$myArray,$myIndex,$myData) {
$myIndex = explode('][',trim($myIndex,'[]'));
$m = &$myArray;
foreach($myIndex as $myNode) {
$myNode = trim($myNode,"'");
$m[$myNode] = NULL;
$m = &$m[$myNode];
}
$m = $myData;
}
// I want this to be $myArray[0][1][2]
myArrayFunc($myArray,$index1,'stuff');
// I want this to be $myArray['cat']['cow']['dog']
myArrayFunc($myArray,$index2,'morestuff');
var_dump($myArray);
There's always the evil eval:
eval('$myArray' . $index1 . ' = "stuff";');
You can use two anonymous functions for this.
$getThatValue = function($array){ return $array[0][1][2]; };
$setThatValue = function(&$array, $val){ $array[0][1][2] = $val; };
$setThatValue($myArray, 'whatever');
$myValue = $getThatValue($myArray);
I have a simple function:
function test(){
//some code
$X_has_val = $Y_has_val= array();
foreach ($A as $id => $row){
if(is_take($id)){
$X_has_val[$id] = $row;
}
}
foreach ($B as $id => $row){
if(is_take($id)){
$Y_has_val[$id] = $row;
}
}
//some code
}
I did this for get the equivalence
function test(){
//some code
$X_has_val = $Y_has_val= array();
foreach(array($A, $B) as $key=>$value){
foreach ($value as $id => $row){
if(is_take($id)){
$X_has_val[$id] = $row;
continue;
$Y_has_val[$id] = $row;
}
}
}
//some code
}
Looks like all you need is array_filter()
$X_has_cc = array_filter($A, 'isTake');
$Y_has_cc = array_filter($B, 'isTake');
like e.g. in
<?php
test();
function test() {
$A = array(1,2,3,4,5,6,7,8,9,10);
$B = array(99,100,101,102,103,104);
$X_has_cc = array_filter($A, 'isTake');
$Y_has_cc = array_filter($B, 'isTake');
var_dump($X_has_cc, $Y_has_cc);
}
// select "even elements"
function isTake($x) {
return 0==$x%2;
}
(and sorry, no, your approach doesn't make much sense ;-))
I'm writing code to recursively replace predefined variables from inside a given string. The variables are prefixed with the character '%'. Input strings that start with '^' are to be evaluated.
For instance, assuming an array of variables such as:
$vars['a'] = 'This is a string';
$vars['b'] = '123';
$vars['d'] = '%c'; // Note that $vars['c'] has not been defined
$vars['e'] = '^5 + %d';
$vars['f'] = '^11 + %e + %b*2';
$vars['g'] = '^date(\'l\')';
$vars['h'] = 'Today is %g.';
$vars['input_digits'] = '*****';
$vars['code'] = '%input_digits';
The following code would result in:
a) $str = '^1 + %c';
$rc = _expand_variables($str, $vars);
// Result: $rc == 1
b) $str = '^%a != NULL';
$rc = _expand_variables($str, $vars);
// Result: $rc == 1
c) $str = '^3+%f + 3';
$rc = _expand_variables($str, $vars);
// Result: $rc == 262
d) $str = '%h';
$rc = _expand_variables($str, $vars);
// Result: $rc == 'Today is Monday'
e) $str = 'Your code is: %code';
$rc = _expand_variables($str, $vars);
// Result: $rc == 'Your code is: *****'
Any suggestions on how to do that? I've spent many days trying to do this, but only achieved partial success. Unfortunately, my last attempt managed to generate a 'segmentation fault'!!
Help would be much appreciated!
Note that there is no check against circular inclusion, which would simply lead to an infinite loop. (Example: $vars['s'] = '%s'; ..) So make sure your data is free of such constructs.
The commented code
// if(!is_numeric($expanded) || (substr($expanded.'',0,1)==='0'
// && strpos($expanded.'', '.')===false)) {
..
// }
can be used or skipped. If it is skipped, any replacement is quoted, if the string $str will be evaluated later on! But since PHP automatically converts strings to numbers (or should I say it tries to do so??) skipping the code should not lead to any problems.
Note that boolean values are not supported! (Also there is no automatic conversion done by PHP, that converts strings like 'true' or 'false' to the appropriate boolean values!)
<?
$vars['a'] = 'This is a string';
$vars['b'] = '123';
$vars['d'] = '%c';
$vars['e'] = '^5 + %d';
$vars['f'] = '^11 + %e + %b*2';
$vars['g'] = '^date(\'l\')';
$vars['h'] = 'Today is %g.';
$vars['i'] = 'Zip: %j';
$vars['j'] = '01234';
$vars['input_digits'] = '*****';
$vars['code'] = '%input_digits';
function expand($str, $vars) {
$regex = '/\%(\w+)/';
$eval = substr($str, 0, 1) == '^';
$res = preg_replace_callback($regex, function($matches) use ($eval, $vars) {
if(isset($vars[$matches[1]])) {
$expanded = expand($vars[$matches[1]], $vars);
if($eval) {
// Special handling since $str is going to be evaluated ..
// if(!is_numeric($expanded) || (substr($expanded.'',0,1)==='0'
// && strpos($expanded.'', '.')===false)) {
$expanded = "'$expanded'";
// }
}
return $expanded;
} else {
// Variable does not exist in $vars array
if($eval) {
return 'null';
}
return $matches[0];
}
}, $str);
if($eval) {
ob_start();
$expr = substr($res, 1);
if(eval('$res = ' . $expr . ';')===false) {
ob_end_clean();
die('Not a correct PHP-Expression: '.$expr);
}
ob_end_clean();
}
return $res;
}
echo expand('^1 + %c',$vars);
echo '<br/>';
echo expand('^%a != NULL',$vars);
echo '<br/>';
echo expand('^3+%f + 3',$vars);
echo '<br/>';
echo expand('%h',$vars);
echo '<br/>';
echo expand('Your code is: %code',$vars);
echo '<br/>';
echo expand('Some Info: %i',$vars);
?>
The above code assumes PHP 5.3 since it uses a closure.
Output:
1
1
268
Today is Tuesday.
Your code is: *****
Some Info: Zip: 01234
For PHP < 5.3 the following adapted code can be used:
function expand2($str, $vars) {
$regex = '/\%(\w+)/';
$eval = substr($str, 0, 1) == '^';
$res = preg_replace_callback($regex, array(new Helper($vars, $eval),'callback'), $str);
if($eval) {
ob_start();
$expr = substr($res, 1);
if(eval('$res = ' . $expr . ';')===false) {
ob_end_clean();
die('Not a correct PHP-Expression: '.$expr);
}
ob_end_clean();
}
return $res;
}
class Helper {
var $vars;
var $eval;
function Helper($vars,$eval) {
$this->vars = $vars;
$this->eval = $eval;
}
function callback($matches) {
if(isset($this->vars[$matches[1]])) {
$expanded = expand($this->vars[$matches[1]], $this->vars);
if($this->eval) {
// Special handling since $str is going to be evaluated ..
if(!is_numeric($expanded) || (substr($expanded . '', 0, 1)==='0'
&& strpos($expanded . '', '.')===false)) {
$expanded = "'$expanded'";
}
}
return $expanded;
} else {
// Variable does not exist in $vars array
if($this->eval) {
return 'null';
}
return $matches[0];
}
}
}
I now have written an evaluator for your code, which addresses the circular reference problem, too.
Use:
$expression = new Evaluator($vars);
$vars['a'] = 'This is a string';
// ...
$vars['circular'] = '%ralucric';
$vars['ralucric'] = '%circular';
echo $expression->evaluate('%circular');
I use a $this->stack to handle circular references. (No idea what a stack actually is, I simply named it so ^^)
class Evaluator {
private $vars;
private $stack = array();
private $inEval = false;
public function __construct(&$vars) {
$this->vars =& $vars;
}
public function evaluate($str) {
// empty string
if (!isset($str[0])) {
return '';
}
if ($str[0] == '^') {
$this->inEval = true;
ob_start();
eval('$str = ' . preg_replace_callback('#%(\w+)#', array($this, '_replace'), substr($str, 1)) . ';');
if ($error = ob_get_clean()) {
throw new LogicException('Eval code failed: '.$error);
}
$this->inEval = false;
}
else {
$str = preg_replace_callback('#%(\w+)#', array($this, '_replace'), $str);
}
return $str;
}
private function _replace(&$matches) {
if (!isset($this->vars[$matches[1]])) {
return $this->inEval ? 'null' : '';
}
if (isset($this->stack[$matches[1]])) {
throw new LogicException('Circular Reference detected!');
}
$this->stack[$matches[1]] = true;
$return = $this->evaluate($this->vars[$matches[1]]);
unset($this->stack[$matches[1]]);
return $this->inEval == false ? $return : '\'' . $return . '\'';
}
}
Edit 1: I tested the maximum recursion depth for this script using this:
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEF'; // GHIJKLMNOPQRSTUVWXYZ
$length = strlen($alphabet);
$vars['a'] = 'Hallo World!';
for ($i = 1; $i < $length; ++$i) {
$vars[$alphabet[$i]] = '%' . $alphabet[$i-1];
}
var_dump($vars);
$expression = new Evaluator($vars);
echo $expression->evaluate('%' . $alphabet[$length - 1]);
If another character is added to $alphabet maximum recursion depth of 100 is reached. (But probably you can modify this setting somewhere?)
I actually just did this while implementing a MVC framework.
What I did was create a "find-tags" function that uses a regular expression to find all things that should be replaced using preg_match_all and then iterated through the list and called the function recursively with the str_replaced code.
VERY Simplified Code
function findTags($body)
{
$tagPattern = '/{%(?P<tag>\w+) *(?P<inputs>.*?)%}/'
preg_match_all($tagPattern,$body,$results,PREG_SET_ORDER);
foreach($results as $command)
{
$toReturn[] = array(0=>$command[0],'tag'=>$command['tag'],'inputs'=>$command['inputs']);
}
if(!isset($toReturn))
$toReturn = array();
return $toReturn;
}
function renderToView($body)
{
$arr = findTags($body);
if(count($arr) == 0)
return $body;
else
{
foreach($arr as $tag)
{
$body = str_replace($tag[0],$LOOKUPARRY[$tag['tag']],$body);
}
}
return renderToView($body);
}