Array to string conversion error in PHP - php

I have following code to backtrace the error ....but its
$traces = debug_backtrace();
foreach ($traces as $k => $v)
{
if ($v['function'] == 'include'
|| $v['function'] == 'include_once'
|| $v['function'] == 'require_once'
|| $v['function'] == 'require')
{
$args = '';
if (isset($v['args']) && is_array($v['args']))
{
$size = count($v['args']);
foreach ($v['args'] as $key => $arg)
{
$args .= $v['args'][$key];
if($key < $size)
{
$args .= ', ';
}
}
}
$traces .= '#' . $k . ' '
. $v['function']
. '('.$args.') called at ['
. $v['file'].':'.$v['line'].']';
}
else
{
$function = (array_key_exists('function',$v)) ?
$v['function'].'() ' : 'function_name';
$file = (array_key_exists('file',$v)) ?
$v['file'] : 'file_name';
$line = (array_key_exists('line',$v)) ?
$v['line'] : 'line';
$traces .= "#{$k} $function called at {$file}:{$line}\n";//This line giving me notice...
}
}
I am getting notice as Array to string conversion here:
$traces .= "#$k $function called at $file:$line\n";
I actually want to convert this array into string. Is there any method or function which can do the conversion without giving me any notice...
How do I correct this?

you begin with:
foreach($traces as $k=>$v) <- $traces here is an array
then you try to do
$traces.= "xxx" <- $traces here is handled as a string
i would rather define a $tracestr string for aggregating text content.

You are not creating array properly
$args .= $v['args'][$key];
You are creating a string.
$args = array();
if(isset($v['args']) && is_array($v['args']))
{
$size = count($v['args']);
foreach ($v['
args'] as $key => $arg)
{
array_push($args,$v['args'][$key]);
// some of your code
}

$trace = debug_backtrace();
foreach($traces as ...)
There's something wrong here. $trace is a Debug Backtrace array. While you foreach($traces) ... which seems undefined. And you append to $traces which is supposed to be a non-scalar to foreach it.
Just name your variables properly and make names different!

Related

How to get the values only if all the keys have matched?

I want to make a method that returns keys and values. But only if the keys include the following string "_1" and "__last".
If only one matches then exit the function, only if the two string are included in the key, return the key with the value for a weather.
$infoList = array("_key_1"=>array("time"=>9, "day"=>"Tuesday", "weather"=>"sunny",
"humidity"=>"80%"),
"_key_2"=>array("time"=>5, "day"=>"Tuesday", "weather"=>"cloudy"),
"_key__last"=>array("time"=>3, "day"=>"Sunday", "weather"=>"rainy"))
public function getData() {
$list = array();
foreach($infoList as $key){
if(preg_match('/(_key)_(_1)/', $key) && preg_match('/(_key)_(__last)/', $key) == TRUE){
$list[$key] = $list[$key]["weather"]
}
}
return $list
}
You are making your life so much more difficult that it need be, use str_contains() its easier than building complex REGEX's and getting very confused by the look of it :)
I also fixed a number of other mistakes, such as the foreach that was not going to work, so check all the code.
It is also better to pass data to a function/method otherwise you get into scoping issues!
$infoList = array("_key_1"=>array("time"=>9, "day"=>"Tuesday", "weather"=>"sunny", "humidity"=>"80%"),
"_key_2"=>array("time"=>5, "day"=>"Tuesday", "weather"=>"cloudy"),
"_key__last"=>array("time"=>3, "day"=>"Sunday", "weather"=>"rainy"));
function getData(Array $infoList) {
$list = [];
$found = 0;
foreach($infoList as $key => $val) {
if( str_contains($key, '_1') || str_contains($key, '__last') ) {
$list[$key] = $val["weather"];
$found++;
}
}
if ( $found >= 2 ) {
return $list;
} else {
return false;
}
}
$res = getData($infoList);
if ( $res !== false ){
print_r($res);
} else {
echo 'Not Found';
}
RESULTS
Array
(
[_key_1] => sunny
[_key__last] => rainy
)
If you want to stick with RegEx, you can use positive lookaheads, the same way you check for passwords characters :
<?php
$pattern = '/^(?=.*_1)(?=.*_last).*$/';
$shouldMatch = [
'_1_last',
'foo_1bar_lasthello',
'_last_1',
'foo_lastbar_1hello'
];
echo 'next ones should match : ' . PHP_EOL;
foreach ($shouldMatch as $item)
{
if (preg_match($pattern, $item))
echo $item . PHP_EOL;
}
$shouldNOTMatch = [
'_2_first',
'bar_lasthello',
'foo_las_1hello'
];
echo 'next ones should NOT match : ' . PHP_EOL;
foreach ($shouldNOTMatch as $item)
{
// v------------ check
if (!preg_match($pattern, $item))
echo $item . PHP_EOL;
}
Output :
next ones should match :
_1_last
foo_1bar_lasthello
_last_1
foo_lastbar_1hello
next ones should NOT match :
_2_first
bar_lasthello
foo_las_1hello

Recursive regex pattern in PHP

I'd like to use tag-style annotations in html text to replace sections of text/html depending on variable names using PHP. The replacement itself works perfectly if not using nested tags.
But if there are nested tags, only the outer one gets replaced.
My regex is this one:
\[\#if(not)?:([a-zA-Z0-9]+)(?:=(.*?))?\].*?\[\#endif:\2\]
You can see this regex in action with example content to parse here:
https://regex101.com/r/rE3fL1/2
I've read about (?R) but can't get it to work.
I tried replacing the .*? in the middle with (.*?|(?R)) but that doesn't even change anything.
How do I change the regex to also capture nested Tags?
Code: ($this->output accesses the Text)
public function output($dbAccess = true) {
// only translate when dbaccess is granted
if ($dbAccess)
$this->localize();
// insert values into template
foreach ( $this->values as $key => $value ) {
$tagToReplace = "[#$key]";
$this->output = str_replace ( $tagToReplace, $value, $this->output );
}
// gather conditional content sections from output
$condis = array();
$conmatches = array ();
preg_match_all ( '/\[\#if(not)?:([a-zA-Z0-9]+)(?:=(.*?))?\].*?\[\#endif:\2\]/s', $this->output, $conmatches );
if (count($conmatches) > 0) {
$c = $conmatches[0];
// if (count($c) > 0)
// echo "found " . count($c[0]) . " conditional tpl statement matches!";
for ($i=0; $i<count($c); $i++) {
$text = $c[$i];
$not = $conmatches[1][$i];
$name = $conmatches[2][$i];
$value = $conmatches[3][$i];
$condis[] = new ConditionalContent($text, $not, $name, $value);
}
// substitute conditional content sections
foreach ($condis as $cc) {
// convenience and readability vars!
$varname = $cc->name();
$vals = &$this->values;
$value = $cc->value();
// if condition is bound to value of variable and not just existence
if ($value != "") {
// del if name == exists(value)
if ($cc->not() && isset($vals[$varname])) {
if ($vals[$varname] == $value) {
$this->delContent($cc->content());
}
}
// del if not exists(value) or value != name
else {
if (!isset($vals[$varname]) || $vals[$varname] != $value) {
$this->delContent($cc->content());
}
}
}
else {
if ( isset($vals[$varname]) && $cc->not() ||
!isset($vals[$varname]) && !$cc->not()) {
$this->delContent($cc->content());
}
}
}
// delete all left over if(not) and endif statements
$this->output = preg_replace('/\[#(?:if(?:not){0,1}|endif):[a-zA-Z0-9]+(=.*?)?\]/', '', $this->output);
}
//else { echo "found no conditional tpl statements"; }
return $this->output;
}

PHP ellipsis using substr and concatenation

foreach($products as $val)
{
$name = $val["name"];
if(strlen($name) > 5){
$name = substr($name,0,5) . '..';
}
}
I have a list of string, and I want to add dot dot at the end of it using PHP, but above code return 0?
If you want to make changes you need to reference & the copy in the foreach.
Example:
foreach($products as &$val) {
// ^ reference
if(strlen($val['name']) > 5) {
$val['name'] = substr($val['name'], 0, 5) . ' ...';
}
}
Or if you are not comfortable this way, could also use the key of the foreach to point it directly to that index.
foreach($products as $key => $val) {
if(strlen($val['name']) > 5) {
$products[$key]['name'] = substr($val['name'], 0, 5) . ' ...';
// ^ use $key
}
}
And lastly, if you do not want any changes at all (just output echo), then this:
foreach($products as $key => $val) {
$name = $val['name'];
if(strlen($name) > 5) {
$name = substr($name['name'], 0, 5) . '...';
}
echo $name; // you forgot to echo
}
your question is a bit unclear as to where you are stuck.
If you want to modify your $products array, then Ghost offered you one solution.
If you simply want an array of shortened product names, I would store them in a new array since you might need the full names later.
$shortNames = array();
foreach($products as $val)
{
$name = $val["name"];
if(strlen($name) > 5){
$name = substr($name,0,5) . '..';
}
$shortNames[] = $name;
}
You wrote
but above code return 0
if this code is inside a function, maybe you simple missed to return the result?
for example with my code, put return $shortNames; at the end of the function

How to simplify this kind of code?

This code is properly working. However, I'm thinking of ways to shorten it since I'm still learning PHP. I'm using this snippet to generate a title for an e-mail I am going to send to somebody.
foreach($_POST as $key => $value) {
if(strpos($key,'cloud') !== false && !$a) {
$title .= "CS ";
$a = true;
}
if(strpos($key,'dco') !== false && !$b) {
$title .= "DC ";
$b = true;
}
if(strpos($key,'comm') !== false && !$c) {
$title .= "BC ";
$c = true;
}
if(strpos($key,'fiber') !== false && !$d) {
$title .= "FC ";
$d = true;
}
}
I'm pretty sure they do the same thing (all of the if statements). If there's anything you can suggest/advice, please let me know!
Cheers!
You can simple create function. This code should work:
foreach($_POST as $key => $value) {
checkstrpos($key,'cloud',$a,$title,"CS ");
checkstrpos($key,'dco',$b,$title,"DC ");
checkstrpos($key,'comm',$c,$title,"BC ");
checkstrpos($key,'fiber',$d,$title,"FC ");
}
function checkstrpos($key,$text, &$variable, &$title, $add) {
if(strpos($key,$text) !== false && !$variable) {
$title .= $add;
$variable = true;
}
}
Another solution without using references:
foreach($_POST as $key => $value) {
list($title, $a) = checkstrpos($key,'cloud',$a,$title,"CS ");
list($title, $b) = checkstrpos($key,'dco',$b,$title,"DC ");
list($title, $c) = checkstrpos($key,'comm',$c,$title,"BC ");
list($title, $d) = checkstrpos($key,'fiber',$d,$title,"FC ");
}
function checkstrpos($key,$text, $variable, $title, $add) {
if(strpos($key,$text) !== false && !$variable) {
$title .= $add;
$variable = true;
}
return array($title, $variable);
}
To me I think that code is simple enough.
If you're attempting to make the code shorter, you risk making it harder to read.
The one comment I have is don't use generic variable names like $a, $b, $c and $d. Use proper descriptive variable names instead.
It's possible that you could swap the positions of these conditions, that is, change
if(strpos($key,'dco') !== false && !$b)
to
if(!$b && strpos($key,'dco') !== false)
But this is more of a micro-optimization than a simplification or change in readability.
Another solution without using a function:
$infos = array(
array('cloud', 'CS', &$a),
array('dco', 'DC', &$b),
array('comm', 'BC', &$c),
array('fiber', 'FC', &$d)
);
foreach($_POST as $k => $v) {
foreach($infos as $info) {
if ( !$info[2] && strpos($k, $info[0]) !== false) {
$title .= $info[1]. ' ';
$info[2] = true;
}
}
}
This isn't the best way though. As suggested in another answer, it'd be better to use a function: an anonymous function (aka closure).

PHP Notice: Undefined property: Tpl::$lbName

I have a class Tpl to mount template with this function (template.php)
function Set($var, $value){
$this->$var = $value;
}
A php file that call the function, example (form.php):
$t->Set("lbAddress","Address");
And a html file with the template with tags (template.html)
<tr><td>[lbAdress]</td></tr>
To print the html I have this function (template.php) - the notice points to this function
function Show_Temp($ident = ""){
// create array
$arr = file($this->file);
if( $ident == "" ){
$c = 0;
$len = count($arr);
while( $c < $len ){
$temp = str_replace("[", "$" . "this->", $arr[$c]);
$temp = str_replace("]", "", $temp);
$temp = addslashes($temp);
eval("\$x = \"$temp\";");
echo $x;
$c++;
}
} else {
$c = 0;
$len = count($arr);
$tag = "*=> " . $ident;
while( $c < $len ){
if( trim($arr[$c]) == $tag ){
$c++;
while( (substr(#$arr[$c], 0 ,3) != "*=>" ) && ($c < $len) ){
$temp = str_replace("[", "$" . "this->", $arr[$c]);
$temp = str_replace("]", "", $temp);
$temp = addslashes($temp);
eval("\$x= \"$temp\";"); //this is the line 200
echo $x;
$c++;
}
$c = $len;
}
$c++;
}
}
}
If the template .html have a line [lbName] and I don't have the line $t->Set("lbName","Name"); at the php code, I receive the error PHP Notice: Undefined property: Tpl::$lbName in ../template.php(200) : eval()'d code on line 1. The solution that I found is add lines like $t->Set("lbName","");, but if I have 50 tags in HTML that I don't use in PHP, I have to add all 50 $t->Set("tag_name","");. The error occurred after migrate to the PHP 5.
Can someone help me? Thanks
Perhaps a better way still would be not to rely on dynamic evaluation through eval (it's generally best to avoid eval where possible), but to replace [lbName] with the value stored in the object directly as and when needed. If you can replace [lbName] with $this->lbName, surely you can also replace it with the value of lBName that you've looked up on-the-fly?
To answer your original question, however:
If I understand correctly, you're setting the values like this:
$t->Set('foo', 'bar');
And – effectively – getting them like this:
$t->foo;
If so, you could implement a __get method to intercept the property references and provide your own logic for retrieving the value; e.g.:
public function __get($key)
{
// You can adapt this logic to suit your needs.
if (isset($this->$key))
{
return $this->$key;
}
else
{
return null;
}
}
In this case, you'd probably be better off using an associative array as the backing store, and then using __get and __set to access it; e.g.:
class Template
{
private $values = array();
public function __get($key)
{
if (array_key_exists[$key, $this->values])
{
return $this->values[$key];
}
else
{
return null;
}
}
public function __set($key, $value)
{
$this->values[$key] = $value;
}
}

Categories