How can I convert an array into a php statement? - php

I have an array like this...
[Summary] => Array
(
[0] => yearManufactured
[1] => &&
[2] => make
[3] => ||
[4] => model
)
how can I convert this array into function calls and operators and then use it to make a comparision, for example turn it into this...
if( $this->yearManufactured() && $this->make() || $this->model() ) {
// do something
} else {
// do something else
}
Methods in class..
public function yearManufactured() {
return true;
}
public function make() {
return false;
}
public function model() {
return true;
}

This seems like something that could actually be a valid use for eval. You can verify that each array item is either an operator or a valid method name, and convert the result of the method call to a boolean string. Putting those things together should result in a string that you can safely eval without worrying about it doing something nasty, other than maybe causing a parse error, which can be caught in PHP 7.
If you find anything in the array that isn't supposed to be there, or the expression doesn't parse, you can return null, or throw an exception, however you want to handle it.
public function evaluateExpressionArray(array $expression) {
// build the expression
$expr = '$result =';
foreach ($expression as $part) {
if ($part == '||' || $part == '&&') {
$expr .= " $part ";
} elseif (method_exists($this, $part)) {
$expr .= $this->$part() ? 'true' : 'false';
} else {
return null;
}
}
// try to evaluate it
try {
eval("$expr;");
} catch (ParseError $e) {
return null;
}
return $result;
}
Be very careful with eval, though. Don't ever put anything into it unless you know exactly what it is.
Here's an example to mess with.

Related

Arrays in php oop

I have array, where i put data depend on the url. But there is the problem, i can not print this array like in the simple php:
$array = ["hi", "name"]; echo $array[1];
what is wrong in my code that i will show, and how i can print the array
Code:
<?php
class Translate {
public $transl = [];
public function getTransl($transl = []) {
if (( isset($_GET['lang']))) {
if ($_GET['lang'] == "en") {
$this->transl = ['word1', 'word2'];
}
if ($_GET['lang'] == "ru") {
$this->transl = ['word3', 'word4'];
}
}
}
}
$test = new Translate();
$test->getTransl([0]);
?>
No idea, why are you using $transl = [] in method parameter when you need specific index, here you can just pass key which you need.
Example:
<?
class Translate {
public $transl = 0;
public function getTransl($transl = '') {
if (( isset($_GET['lang']))) {
if ($_GET['lang'] == "en") {
$this->transl = ['word1', 'word2'];
}
if ($_GET['lang'] == "ru") {
$this->transl = ['word3', 'word4'];
}
}
return $this->transl[$transl];
}
}
$test = new Translate();
echo $test->getTransl(0); // this will print `word1` if $_GET['lang'] equal to `en`
?>
In your code, you are not using either echo or return in your method to get the result, and you are not matching $transl with $this->transl anywhere to get the specific index.
First, you don't pass the index as a parameter. You use it as an index. Proper syntax would be:
$test->getTransl()[0];
That assumes that $test->getTransl() returns an array. But it doesn't. It doesn't return anything. It just sets the class attribute $transl. So, you have to do it in two lines:
$test->getTransl(); // This sets the attribute
$test->transl[0]; // This uses the attribute
But, that goes against that the method implies. The method implies that it returns the transl attribute. So, you SHOULD return it in the function with:
return this->transl;
Then, you can use:
$test->getTransl()[0];
Of course, this won't print anything. You need to precede with with echo or print:
echo $test->getTransl()[0];
I think you'll just need to return the output.
Let's say you have a file named test.php on your server
class Translate {
public $transl = [];
public function getTransl($transl = []) {
if (( isset($_GET['lang']))) {
if ($_GET['lang'] == "en") {
$this->transl = ['word1', 'word2'];
}
if ($_GET['lang'] == "ru") {
$this->transl = ['word3', 'word4'];
}
}
return $this->transl;
}
}
$test = new Translate();
$output=$test->getTransl([0]);
echo "<pre>";
print_r($output);
echo "</pre>";
Running http://server/{{enterfolderhere}}/test.php?lang=en in your browser will give
Array
(
[0] => word1
[1] => word2
)
Running http://server/{{enterfolderhere}}/test.php?lang=ru in your browser will give
Array
(
[0] => word3
[1] => word4
)
There are a few issues with your code as others have pointed out. But from a code structure point of view, there are some more fundamental issues (IMHO).
If you are going to create a translator, basing it on if $_GET variables means it can be difficult to test. In this example, you send in a language you want in the constructor and then the class will just set the private translator variables to the table of translations.
Secondly - using numeric values for the word your after can be prone to errors (so can this method, but less so). In this case, the key of the translation is the word you want to start with and the value is the new word, so rather than
echo $test->getTransl(0);
you use
echo $russianTrans->getTransl("word2");
This is the code, hope it helps...
class Translate {
// Use private variables whenever possible
private $transl = [];
public function __construct( string $lang ) {
if ($lang == "en") {
$this->transl = ['word1' => 'word1', 'word2' => 'word2'];
}
if ($lang == "ru") {
$this->transl = ['word1' => 'word3', 'word2' => 'word4'];
}
}
public function getTransl($word) {
return $this->transl[$word];
}
}
$russianTrans = new Translate($_GET['lang']); // Or hardcode it to 'ru' for example
echo $russianTrans->getTransl("word2");

Maintain Element in PHP Array And Update in PHP Class

I have one PHP class as below (part of the code):
class myclass{
private static $arrX = array();
private function is_val_exists($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && $this->is_val_exists($needle, $element))
return true;
}
return false;
}
//the $anInput is a string e.g. Michael,18
public function doProcess($anInput){
$det = explode(",", $anInput);
if( $this->is_val_exists( $det[0], $this->returnProcess() ) ){
//update age of Michael
}
else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
));
}
}
public function returnProcess(){
return self::$arrX;
}
}
The calling code in index.php
$msg = 'Michael,18';
myclass::getHandle()->doProcess($msg);
In my webpage says index.php, it calls function doProcess() over and over again. When the function is called, string is passed and stored in an array. In the next call, if let's say same name is passed again, I want to update his age. My problem is I don't know how to check if the array $arrX contains the name. From my own finding, the array seems to be re-initiated (back to zero element) when the code is called. My code never does the update and always go to the array_push part. Hope somebody can give some thoughts on this. Thank you.
There is a ) missing in your else condition of your doProcess() function, it should read:
else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
)); // <-- there was the missing )
}
Here is a complete running solution based on your code:
<?php
class myclass{
private static $arrX = array();
private function is_val_exists($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && $this->is_val_exists($needle, $element))
return true;
}
return false;
}
//the $anInput is a string e.g. Michael,18
public function doProcess($anInput){
$det = explode(",", $anInput);
if( $this->is_val_exists( $det[0], $this->returnProcess() ) ){
//update age of Michael
for ($i=0; $i<count(self::$arrX); $i++) {
if (is_array(self::$arrX[$i]) && self::$arrX[$i]['name'] == $det[0]) {
self::$arrX[$i]['age'] = $det[1];
break;
}
}
} else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
));
}
}
public function returnProcess(){
return self::$arrX;
}
}
$mc = new myclass();
$mc->doProcess('Michael,18');
$mc->doProcess('John,23');
$mc->doProcess('Michael,19');
$mc->doProcess('John,25');
print_r($mc->returnProcess());
?>
You can test it here: PHP Runnable
As I said in comments, it looks like you want to maintain state between requests. You can't use pure PHP to do that, you should use an external storage solution instead. If it's available, try Redis, it has what you need and is quite simple to use. Or, if you're familiar with SQL, you could go with MySQL for example.
On a side note, you should read more about how PHP arrays work.
Instead of array_push, you could have just used self::$arrX[] = ...
Instead of that, you could have used an associative array, e.g. self::$arrX[$det[0]] = $det[1];, that would make lookup much easier (array_key_exists etc.)
Can you try updating the is_val_exists as follows:
private function is_val_exists($needle, $haystack) {
foreach($haystack as $element) {
if ($element['name'] == $needle) {
return true;
}
return false;
}

Check if all elements of array equal to something

Have
$my_arr_1 = array ("denied","denied","denied");
$my_arr_2 = array ("denied","denied","allowed");
Need a func that would check if all elements in the array equal to something:
in_array_all("denied",$my_arr_1); // => true
in_array_all("denied",$my_arr_2); // => false
Is there a php native function like in_array_all?
If not, what would be the most elegant way to write such a func?
function in_array_all($value, $array)
{
return (reset($array) == $value && count(array_unique($array)) == 1);
}
function in_array_all($needle,$haystack){
if(empty($needle) || empty($haystack)){
return false;
}
foreach($haystack as $k=>$v){
if($v != $needle){
return false;
}
}
return true;
}
And if you wanted to get really crazy:
function in_array_all($needle,$haystack){
if(empty($needle)){
throw new InvalidArgumentException("$needle must be a non-empty string. ".gettype($needle)." given.");
}
if(empty($haystack) || !is_array($haystack)){
throw new InvalidArgumentException("$haystack must be a non-empty array. ".gettype($haystack)." given.");
}
foreach($haystack as $k=>$v){
if($v != $needle){
return false;
}
}
return true;
}
I don't know the context of your code. But what about reversing the logic? Then you are able to use PHP's native function in_array.
$my_arr_1 = array ("denied","denied","denied");
$my_arr_2 = array ("denied","denied","allowed");
!in_array("allowed", $my_arr_1); // => true
!in_array("allowed", $my_arr_2); // => false
This entirely depends on your data set of course. But given the sample data, this would work. (Also, notice the negation ! in front of each method call to produce the desired boolean result).
Another solution using array_count_values():
function in_array_all(array $haystack, $needle) {
$count_map = array_count_values($haystack);
// in your case: [ 'denied' => 2, 'allowed' => 1 ]
return isset($count_map[$needle]) && $count_map[$needle] == count($haystack);
}
Richard's solution is best but does not have one closing paren ;-) - here is fixed and abridged:
function in_array_all($needle,$haystack)
{
if( empty($needle) || empty($haystack) ) return false;
foreach($haystack as $v)
{
if($v != $needle) return false;
}
return true;
}

Is there a better way to loop two associative arrays to match their values?

I'm parsing the HTTP_ACCEPT_LANGUAGE header to get users' language and I'm building a class to do that.
Actually I build an associative array ("$this->user_lang") where keys are the language (such as "en-us", "it-it", "it-ch" etc) and the value is the quality factor (so I can order languages).
Then I have another associative array named "$this->installed_langs" where I declare supported language and locales (in the form "en" => "en_US", "it" => "it_IT").
All I want to do is try to match one of the key of "$this->user_lang" with one of the "$this->installed_langs" (without care of the local zone after the "-") and return the first occurrence (with no care for other matching case).
I ended up with this method but it seems a bit too complex...
public function show() {
$g_locale = null;
foreach ($this->user_lang as $lang => $q) {
foreach($this->installed_langs as $valid => $locale) {
if (strpos($lang, $valid) !== false) {
if ($g_locale === null) $g_locale = $locale;
}
}
}
// debug:
echo $g_locale;
}
I hope I have explained it well, btw if you need more informations, please, ask me.
Try this
public function show() {
$g_locale = null;
foreach ($this->user_lang as $lang => $q) {
if ( array_key_exists( $lang, $this->installed_langs ) ) {
$g_locale = $this->installed_langs[$lang];
}
}
}
function show() {
$g_locale = null;
foreach ($this->user_lang as $lang => $q) {
$_key=explode($lang, '-'); // 'en-us' => 'array('en', 'us')
$key=$_key[0]; // 'en'
if ( array_key_exists( $key, $this->installed_langs ) ) {
$g_locale = $this->installed_langs[$key];
}
}
}

Class instance variables becoming null in php

I have this PHP class, whose purpose is to fetch some configuration data from a database and store it for later use:
class GSConfig {
private $configurationData;
private $repository;
public function __construct($pRepository) {
$this->repository = $pRepository;
$this->configurationData = $this->InitializeConfiguration();
}
public function InitializeConfiguration() {
$result = $this->repository->configLoadAll();
if ( $result['data'] ) {
$conf_array = $result['data'];
foreach ( $conf_array as $row) {
$code = strtolower($row ['code']);
$value = strtolower($row ['value']);
//if ($value == "true") $value = (bool)true;
//if ($value == "false") $value = (bool)false;
$this->configurationData[$code] = $value;
}
} else {
$this->configurationData = null;
}
print_r($this->configurationData);
}
public function getConfigValue($key) {
$key = strtolower($key);
if ($this->configurationData != null) {
if( isset($this->configurationData[$key])) {
return $this->configurationData[$key];
}
} else if ($this->configurationData == null) {
// If we reach this code, something went wrong
// (TODO: throw Exception)
echo "<p>Tick</p>";
}
}
}
InitializeConfiguration gets the data and stores it as an array in the $configurationData property. This is working as expected as shown by the output of the print_r function.
However, after initializing, if i attempt to read any value from the $configurationData, i get Tick. Somehow the variable becomes null after the Initialization.
The output would be something like:
print_r output:
Array ( [show_cart] => true [order_mail] => order#shop.de [debug_mode] => true [branch_mode] => true [default_branch] => 1 [agb_file] => agb.txt [kat_order] => k_nr [show_rows] => 5 [product_order] => p_produktnr [cost_per_wu] => 0.66 [message_lang] => eng [free_shipping] => true [free_ship_amt] => 25 [special_price] => true [discounts] => true [cat_show_mode] => all [price_att] => ersatzpreis [mwst_att] => mehrwertsteuer [aktionsp_att] => aktionspreis [katalog_mode] => per_branch )
further output:
Tick
Tick
...
Tick
Anyone knows why this is happenning? Btw, my PHP version is 5.3.1
you're assigning the return value of InitializeConfiguration() but there's no return statement in this function (defaults to "return null").
I suspect it's because in your constructor, you assign $this->configurationData to the return value of InitializeConfiguration(). But it doesn't look like InitializeConfiguration() returns anything. I think the easiest way to fix this is to change:
$this->configurationData = $this->InitializeConfiguration();
to:
$this->InitializeConfiguration();
The problem is that you're assigning the return value of InitializeConfiguration to $this->configurationData inside your constructor, which will be null.
The following remains sound advice:
Strongly suspect your error is arising from your using the incorrect comparison operator.
Never, ever do this in PHP:
if ($this->configurationData == null)
When testing against null, false or 0, always use === which checks that both the values and types of each variable are the same. Simply using == will cast one side to the type of the other before the conversion.
The following are all true when using the == operator:
null == 0;
array() == null;
null == false;
false == 0;
You also shouldn't be using else if ($this->configurationData == null) in getConfigValue; use a simple else since your intent seems to be to cover all other cases.

Categories