Warning message displayed due to array_count_values() - php

I am using Codeigniter framework of PHP and trying to extract keywords from the page. The complete code for reference can be seen here. It is not ready-made though.
The issue is due to the array function in the following line:
$keywordCounts = array_count_values( $words );
The error message being displayed is as follows:
A PHP Error was encountered
Severity: Warning
Message: array_count_values() [function.array-count-values]: Can only count STRING and INTEGER values!
EDITED: The array $words for reference can be found here.
There are no special symbols or invalid characters to my knowledge in the $words array. Hyphens and periods are not read by the function or is there some other issue ?

you have null values in your array. you have to replace them before working with array_count_values like this:
$x = array('s'=>'ss', 'a',4 , 'sss' => null);
$ar = array_replace($x,array_fill_keys(array_keys($x, null),''));
$v = array_count_values($ar);
var_dump($v);
which will result:
array (size=4)
'ss' => int 1
'a' => int 1
4 => int 1
'' => int 1

Related

How to get Key from this string array in PHP [duplicate]

This question already has answers here:
How create an array from the output of an array printed with print_r?
(11 answers)
Closed 1 year ago.
Array ( [status] => 1 [message] => Logged In Successfully. )
I Want to access status from this array like string.
I fetch this Response from API.
It's look not good.not like array or not like json.
I am not able to access key,so any one can help me, now.
You could achieve this using preg_match perhaps? See it working over at 3v4l.org but it is not a very dynamic solution and I'm assuming the status will always be a single integer.
preg_match('/(\Sstatus\S => \d)/',
'Array ( [status] => 1 [message] => Logged In Successfully. )',
$matches
);
if(!empty($matches))
{
$status = (int) $matches[0][strlen($matches[0]) -1]; // 1
}
To improve #Jaquarh's answer, you could write this function that helps you extract the values using any desired string, key and expected type.
I have added a few features to the function like not minding how many spaces come between the => separator in the string, any value-type matching, so that it can retrieve both numeric and string values after the => separator and trimming of the final string value. Finally, you have the option of casting the final value to an integer if you want - just supply an argument to the $expected_val_type argument when you call the function.
$my_str is your API response string, and $key_str is the key whose value you want to extract from the string.
function key_extractor($my_str, $key_str, $expected_val_type=null) {
// Find match of supplied $key_str regardless of number of spaces
// between key and value.
preg_match("/(\[" . $key_str . "\]\s*=>\s*[\w\s]+)/", $my_str, $matches);
if (!empty($matches)) {
// Retrieve the value that comes after `=>` in the matched
// string and trim it.
$value = trim(substr($matches[0], strpos($matches[0], "=>") + 2));
// Cast to the desired type if supplied.
if ($expected_val_type === 'int') {
return ((int) $value);
}
return $value;
}
// Nothing was found so return null.
return NULL;
}
You could then use it like this:
key_extractor($res, 'status', 'int');
$res is your API response string.

PHP array to string conversion notice with CachingIterator

I have done some searching on Stackoverflow already on this topic, however as far as I can tell, I am not treating an array as a string ?
The message I am getting is :
Array to string conversion in X on line 42
Line 42 of my code is the opening of a foreach loop :
foreach ($collection as $element) {
Variable $collection is a caching iterator that is based on database output:
$collection=new \CachingIterator(new \ArrayIterator($this->dbData));
If I print_r() on $this->dbData, I certainly get an array:
Array
(
[0] => Array
(
[c_id] => A
)
[1] => Array
(
[c_id] => B
)
So, in summary:
We have a confirmed output of an array
We know that ArrayIterator() expects an array as argument
We know that CachingIterator() expects an Iterator as argument
We know that foreach() can loop over an Iterator
TL;DR I am really not sure what I am treating as string here ?
EDIT TO ADD....
Even if I greatly simplify my code, I can still reproduce:
<?php
error_reporting (E_ALL | E_STRICT);
ini_set ('display_errors', 1);
$arrX=array(array("c_id"=>"A"),array("c_id"=>"B"));
$collection=new \CachingIterator(new \ArrayIterator($arrX));
foreach($collection as $element) {
echo $element["c_id"].PHP_EOL;
}
Notice: Array to string conversion in /Users/bp/tmp/test.php on line 6
A
Notice: Array to string conversion in /Users/bp/tmp/test.php on line 6
B
The short answer is, you're inadvertently asking the CachingIterator to convert the sub-arrays to strings during iteration. To not do this, don't use the CachingIterator::CALL_TOSTRING or CachingIterator::TOSTRING_USE_INNER flags.
You can set no flags, by using 0 as the value for the $flags parameter, or use a different flag: this can be done in the constructor, or after initialisation by using CachingIterator::setFlags().
For example:
$array = [["c_id" => "A"], ["c_id" => "B"]];
$collection = new CachingIterator(new ArrayIterator($array), 0);
foreach ($collection as $element) {
// no E_NOTICE messages, yay!
}
And a few words by way of explanation...
By default, the CachingIterator class sets the CachingIterator::CALL_TOSTRING flag as noted in the PHP manual page on CachingIterator.
public __construct ( Iterator $iterator [, int $flags = self::CALL_TOSTRING ] )
When this flag (or the CachingIterator::TOSTRING_USE_INNER flag) is set, and the CachingIterator::next() method is called (i.e. during iteration) the current value (in this case each sub-array) or the inner iterator (in this case, the ArrayIterator), respectively, is converted to a string and saved internally. This string value is what is returned from CachingIterator::__toString() when one of those flags is used.
When using any of the other flags, the above is not done when calling CachingIterator::next().
You need CachingIterator::FULL_CACHE per this PHP docs comment
<?php
$arrX = array(
array( "c_id" => "A" ),
array( "c_id" => "B" )
);
$collection = new \CachingIterator( new \ArrayIterator( $arrX ), CachingIterator::FULL_CACHE );
foreach( $collection as $element )
{
echo $element["c_id"].PHP_EOL;
}

foreach loop scope with multidimensional arrays

Can someone explain the output of this code?
Why is it "fb" instead of "100100"?
$items = array();
$items[] = "foo";
$items[] = "bar";
foreach($items as $item) {
$item['points'] = 100;
}
foreach($items as $item) {
echo $item['points']; //output: "fb"
}
You loop though the $items array, which has two elements.
First: foo and second: bar. E.g.
Array (
[0] => foo
[1] => bar
)
Now you access them like this:
echo $item['points'];
PHP will convert points which is a string into an integer, as you can see from the manual warning:
Warning: [...] Non-integer types are converted to integer. [...]
Which in your case will be 0.
And so you access the two values (strings) as array:
string: f o o
index: 0 1 2 //$index["points"] -> $index[0]
string: b a r
index: 0 1 2 //$index["points"] -> $index[0]
So you print the first character of both strings (e.g. foo and bar), which are:
fb
EDIT:
Also worth to note here is, that PHP only silently converts it with PHP <5.4 from newer version you will get a warning, as from the manual:
As of PHP 5.4 string offsets have to either be integers or integer-like strings, otherwise a warning will be thrown. Previously an offset like "foo" was silently cast to 0.
Which in your case with PHP >=5.4 you would get:
Warning: Illegal string offset 'points' ...
I found this question intriguing.
I had my own walk-through and here is the result.
$items is defined as follows.
$items = [
0 => "foo",
1 => "bar"
];
Then, goes into the foreach loop.
foreach($items as $item) {
$item['points'] = 100;
}
At the beginning, $item contains a string "foo". The [] syntax is dominantly used for associative arrays, so it tricks us that $item might be an array, which is not the case. A less well-known usage of the [] is to get/set a single character in a string via [int] or {int} expression, as #Rizier123 has noted in his answer. For example, a "string"[0] gives "s". So, the following code
$item['points'] = 100;
is virtually similar to
"foo"['points'] = 100;
Now, a non-integer value given as a character position of a string, raises a PHP warning, and the position (here 'points') will be force-converted to an integer.
// Converting a string to integer:
echo intval('points'); // gives 0
As a result, the "foo"['points']" statement becomes "foo"[0], so
"foo"[0] = 100;
Now, the assignment part. The [] syntax operates on a single character. The numeric 100 is first converted to a string "100" and then only the first character is taken out for the assignment operation(=). The expression is now similar to
"foo"[0] = "1"; // result: "1oo"
To make things a bit twisted, the modified value of $item( which is "1oo") is not preserved. It's because the $item is not a reference. See https://stackoverflow.com/a/9920684/760211 for more information.
So, all the previous operations are negligible in terms of the end result. The $items are intact in the original state.
Now, in the last loop, we can see that the $item['point'] statement tries to read a character out of a string, in an erroneous way.
foreach($items as $item) {
echo $item['points']; //output: "fb"
}
echo "foo"[0]; // "f"
echo "boo"[0]; // "b"
You're not actually modifying the array by doing $items as $item. $item is its own variable, so it would make sense that you get the correct output when printing within that loop.

Indexing into an array returned by a variable variable in PHP

I'm just wondering about how variable variables that point to Arrays handle. Take the code below:
$a = new stdClass();
$a->b = array('start' => 2);
$c = 'b';
$d = 'start';
print $a->$c; // => Array
print $a->$c['start']; // => Array
print $a->$c[0]; // => Array
print $a->$c[0][0]; //=> PHP Fatal error: Cannot use string offset as an array in php shell code on line 1
The first print I expect, the second one I don't, or the 3rd. The 4th is expected after realizing that the evaluation of $a->$c is apparently a string. But then why does this work:
$t = $a->$c;
print $t['start']; //=> 2
I'm asking more because I'm curious than I need to know how to nicely do
$e = 'start';
$a->$c[$e]
Anyone know why I can't index directly into the array returned by the variable variable usage?
It comes down to order of operations and how PHP type juggles. Hint: var_dump is your friend, echo always casts to a string so it is the worst operation for analyzing variable values, esp in debug settings.
Consider the following:
var_dump($a->$c); // array (size=1) / 'start' => int 2
var_dump($a->$c['start']); // array (size=1) / 'start' => int 2
var_dump($a->b['start']); // int 2
var_dump($c['start']); // string 'b' (length=1)
The key here is how PHP interprets the part of $c['start'] (include $c[0] here as well). $c is the string 'b', and when attempting to get the 'start' index of string 'b' this simply returns the first character in the string, which happens to simply be the only letter (b) in the string. You can test this out by using $c = 'bcdefg'; - it'll yield the same result (in this specific case). Also, $c['bogus'] will yield the exact same thing as $c['start']; food for thought, and make sure you do the required reading I linked to.
So with this in mind (knowing that $c['start'] reluctantly returns 'b'), the expression $a->$c['start'] is interpreted at $a->b. That is, the order is $a->($c['start']) and not ($a->$c)['start'].
Unfortunately you can't use () nor {} to steer the parser (PHP SCREAMs), so you won't be able to accomplish what you want in a single line. The following will work:
$e = 'start';
$interim = $a->$c;
echo $interim[$e];
Alternatively, you can cast your arrays as objects (if you have the luxury):
$a->$c = (object) $a->$c; // mutate
var_dump($a->$c->$e);
$interim = (object) $a->$c; // clone
var_dump($interim->$e);
...by the way, referring back up to $c['start'] and $c[0], in regards to $c[0][0] you simply can't do this because $c[0] is the character b in string 'b'; when access the character/byte b it will not have a property of [0].
$a->$c[0]; is actually equal to: array('start' => 0)
so when you did:
print $a->$c[0][0];
You are trying to load an array element from $a->$c[0] at index 0 which does not exists.
however, this will work:
print $a->$c[0]['start'];

Error encountered when getting values from array with sting values

I am using the following array:
$words = $xpath->query('//div[#id="relatedSearches"]/a');
$related_words=array();
foreach ($words as $word) {
$related_words[]=trim($word->nodeValue);
}
var_dump($related_words); // to debug
and the output is:
array
0 => string 'internet books' (length=14)
1 => string 'internet business' (length=17)
2 => string 'internet marketing' (length=18)
and in my code, at a later stage, I use the following code segment to assign values to another array:
$values = array_values($related_words);
Everything is okay, if the output of $related_words does not contain spaces e.g
<li>internet <li>book <li>business
Whenever a space is encountered in input array $related_words I get the error:
Catchable fatal error: Object of class DOMElement could not be converted to string in line 22
Line 22 is $values = array_values($input);
Anyone can please give me a solution to this? Or help?
I searched the same error on stackoverflow but failed to get help..

Categories