PHP - what do the curly brackets inside square brackets do? - php

I'm following a tutorial and this piece of code came up:
for ($i=0; $i < $inlen ; ++$i) {
if (isset($this->morse[$in{$i}])) {
$out .= $this->morse[$in{$i}];
}
return $out;
}
$in is the key we're looking for in the morse array, but what does the $i in curly brackets represent in regards to the key=>value?
Thank you.

In this case, this is not part of a variable variable but rather String access (like getCharAt()). See the manual for more information.
$in{$i}
Becomes the character at $ith position of the string $in.
${'in'.$i}
Would be the variable variable in$i ($in0, $in1, ...)
This also makes sense as $inlen supposedly is strlen($in) and so the loop goes through each character of $in, one at a time.

Related

How does PHP determine whether a variable is an array or a string?

I'm confused as to how PHP determines whether a variable is a string or an array. It seems to depend on the operators being used.
Here's an example:
<?php
$z1 = "abc";
$out = "";
for ($i = 0; $i < strlen($z1); $i++)
{
// $out[$i] = $z1[$i];
$out = $out.$z1[$i];
}
print $out;
?>
In the above version $out becomes a string (print $z1 shows "abc"). However, if I use the first line $out[$i] = $z1[$i];, $out becomes an array.
Can someone please clarify why this happens, and if its possible to access a string's characters with square brackets without converting the output to an array?
The definition of a string in PHP is considered a set of data writen in linear format (i.e: $var = "username=SmokeyBear05,B-day=01/01/1980";)
An array however is a set of data broken down into several parts. A sort of list format if you will. As an example I've written the data string from before, into an array format...
Array(['username']=>"SmokeyBear05", ['B-day']=>"01/01/1980")
Now strings are generally defined as such: $var="Your String";
Arrays however can be written in three different formats:
$var1 = array('data1','data2','data3');
$var2 = array('part A'=>'data1','part B'=>'data2','part C'=>'data3');
The output of var1 starts the index value at 0. The output of var2 however, sets a custom index value. Now the third way to write an array (least common format) is as such:
$var[0]="data1";
$var[1]="data2";
$var[2]="data3";
This takes more work, but allows you to set the index.
Most web developers working with PHP will set data from an external source as a string to deliver it to another PHP script, and then break it down into an array using the explode() function.
When you define variable $out = "", for loop doesn't understand this variable as string value. If you set $out[$i] value, by default, it was treated as an array.
If you want to get the output result as string value, you can define $out = "a" to make sure it's a string variable.

Curly brace variable in array name, PHP

I know there are a lot of similar questions on here, and I think I've read them all. My problem is that I am attempting to loop through a list of arrays and grab one value from each. The arrays have been set up by a third party, and I don't have the access to configure how I am receiving them. Here's what I have so far:
for ($i = 0; $i < $length; $i++) {
// Both of these work and return the value I need
echo $post->related_credits_0_related_show[0];
echo "{$post->related_credits_0_related_show[0]}"
// But none of these do, and I need to loop through a handful of arrays
echo "{$post->related_credits_{$i}_related_show[0]}";
echo "{$post->related_credits_${i}_related_show[0]}";
echo "{$post->related_credits_{${i}}_related_show[0]}";
echo "{$post->related_credits_".$i."_related_show[0]}";
}
I've tried many (many!) more combinations that I won't include. I've also tried converting $i to a string. Been knocking my head against this for awhile.
Thanks ahead of time for any help.
You need to use variable variables here. The basic usage is as follows:
$var = 'Hello there!';
$foo = 'var';
echo $$foo;
^^--- note the double $-sign
This will output:
Hello there!
Instead of $$foo, you can also write the following:
echo ${"$foo"};
If the variable name is more complex, you can can also do:
echo ${"some_stuff_{$foo}_more_stuff"};
In this case, the string that denotes the variable name contains a variable, and that variable is also wrapped inside curly braces ({}). This is done in order to avoid problems with constants, array indexes etc. But if your use-case doesn't involve any of those, you don't have to worry about it.
For your specific problem, you can use the following:
for ($i=0; $i < $length; $i++) {
$post->{"related_credits_{$i}_related_show"}[0];
}
Or, if you prefer concatenation:
for ($i=0; $i < $length; $i++) {
$res = $post->{'related_credits_'.$i.'_related_show'}[0];
}
See the documentation on Variable Variables for more information.
You can use this:
$varname = "related_credits_$i_related_show";
$array = $post->$varname;
echo $array[0];
A shorter form would be:
$post->{"related_credits_{$i}_related_show"}[0];
Here you find all about so called "variable variables" : http://www.php.net/manual/en/language.variables.variable.php

PHP "Use of undefined constant length" Array to string conversion

Can someone tell me why the constant length isn't defined? I'm using glob to find and put all .txt files into an array then using for to loop through them echoing them out.
$filew = glob("/xampp/htdocs/new/*.txt");
for($n=0; $n<$filew.length; $n++) {
$filew['$n'] = substr($filew['$n'], 18, -4);
echo $filew['n'] . " ";
}
The error message indicates the problem lines in the second line, someone told me to put array content into quote marks but it hasn't worked. Thank you
PHP arrays don't have a length property. You should use count instead
$filew = glob("/xampp/htdocs/new/*.txt");
for($n = 0; $n < count($filew); $n++) {
$filew[$n] = substr($filew[$n], 18, -4);
echo $filew[$n] . " ";
}
You also have some errors in the way you are accessing your array. Using a single quote will cause the variable inside to not be rendered. Using $filew['$n'] will not give you a numeric value for $n. It will give a literal string with the value $n. Remove the single quotes should be just fine.

PHP: Counting elements using for loops

I would like to count numeric values in a group of two for equal values. For example for list of values 1,2,3,3,3,3,3,3,3,3,5,5,6
I should have 1,2,(3,3),(3,3),(3,3),(3,3),(5,5),6
That is when I decide to count the first (3,3) are counted as 1. Therefore in this case I should have $count=8 instead of $count=13 for all values. I have tried to do some for loops and if statements but I get wrong results. Any idea is highly appreciated. Thanks
Note: the pairs have to be adjacent to be regarded as 1.
$list = array(1,2,3,3,3,3,3,3,3,3,5,5,6);
$counter = 0;
foreach($list as $number)
{
if(isset($previous) and $previous === $number)
{
unset($previous);
}
else
{
$previous = $number;
$counter++;
}
}
echo $counter; // 8
Regular expression solution with back references:
$s = '1,2,3,3,3,3,3,3,3,3,5,5,6';
echo count(explode(',', preg_replace('/(\d+),\\1/', '\\1', $s)));
Output:
8
The regular expression matches a number and then uses a back reference to match the number adjacent to it. When both are matched, they are replaced by one number. The intermediate result after the preg_replace is:
1,2,3,3,3,3,5,6
After that, the count is performed on the comma separated values.

Remove composed words

I have a list of words in which some are composed words, in example
palanca
plato
platopalanca
I need to remove "plato" and "palanca" and let only "platopalanca".
Used array_unique to remove duplicates, but those composed words are tricky...
Should I sort the list by word length and compare one by one?
A regular expression is the answer?
update: The list of words is much bigger and mixed, not only related words
update 2: I can safely implode the array into a string.
update 3: I'm trying to avoid doing this as if this was a bobble sort. there must be a more effective way of doing this
Well, I think that a buble-sort like approach is the only possible one :-(
I don't like it, but it's what i have...
Any better approach?
function sortByLengthDesc($a,$b){
return strlen($a)-strlen($b);
}
usort($words,'sortByLengthDesc');
$count = count($words);
for($i=0;$i<=$count;$i++) {
for($j=$i+1;$j<$count;$j++) {
if(strstr($words[$j], $words[$i]) ){
$delete[]=$i;
}
}
}
foreach($delete as $i) {
unset($words[$i]);
}
update 5: Sorry all. I'm A moron. Jonathan Swift make me realize I was asking the wrong question.
Given x words which START the same, I need to remove the shortests ones.
"hot, dog, stand, hotdogstand" should become "dog, stand, hotdogstand"
"car, pet, carpet" should become "pet, carpet"
"palanca, plato, platopalanca" should become "palanca, platopalanca"
"platoother, other" should be untouchedm they both start different
I think you need to define the problem a little more, so that we can give a solid answer. Here are some pathological lists. Which items should get removed?:
hot, dog, hotdogstand.
hot, dog, stand, hotdogstand
hot, dogs, stand, hotdogstand
SOME CODE
This code should be more efficient than the one you have:
$words = array('hatstand','hat','stand','hot','dog','cat','hotdogstand','catbasket');
$count = count($words);
for ($i=0; $i<=$count; $i++) {
if (isset($words[$i])) {
$len_i = strlen($words[$i]);
for ($j=$i+1; $j<$count; $j++) {
if (isset($words[$j])) {
$len_j = strlen($words[$j]);
if ($len_i<=$len_j) {
if (substr($words[$j],0,$len_i)==$words[$i]) {
unset($words[$i]);
}
} else {
if (substr($words[$i],0,$len_j)==$words[$j]) {
unset($words[$j]);
}
}
}
}
}
}
foreach ($words as $word) {
echo "$word<br>";
}
You could optimise this by storing word lengths in an array before the loops.
You can take each word and see, if any word in array starts with it or ends with it. If yes - this word should be removed (unset()).
You could put the words into an array, sort the array alphabetically and then loop through it checking if the next words start with the current index, thus being composed words. If they do, you can remove the word in the current index and the latter parts of the next words...
Something like this:
$array = array('palanca', 'plato', 'platopalanca');
// ok, the example array is already sorted alphabetically, but anyway...
sort($array);
// another array for words to be removed
$removearray = array();
// loop through the array, the last index won't have to be checked
for ($i = 0; $i < count($array) - 1; $i++) {
$current = $array[$i];
// use another loop in case there are more than one combined words
// if the words are case sensitive, use strpos() instead to compare
while ($i < count($array) && stripos($array[$i + 1], $current) === 0) {
// the next word starts with the current one, so remove current
$removearray[] = $current;
// get the other word to remove
$removearray[] = substr($next, strlen($current));
$i++;
}
}
// now just get rid of the words to be removed
// for example by joining the arrays and getting the unique words
$result = array_unique(array_merge($array, $removearray));
Regex could work. You can define within the regex where the start and end of the string applies.
^ defines the start
$ defines the end
so something like
foreach($array as $value)
{
//$term is the value that you want to remove
if(preg_match('/^' . $term . '$/', $value))
{
//Here you can be confident that $term is $value, and then either remove it from
//$array, or you can add all not-matched values to a new result array
}
}
would avoid your issue
But if you are just checking that two values are equal, == will work just as well as (and possibly faster than) preg_match
In the event that the list of $terms and $values are huge this won't come out to be the most efficient of strategies, but it is a simple solution.
If performance is an issue, sorting (note the provided sort function) the lists and then iterating down the lists side by side might be more useful. I'm going to actually test that idea before I post the code here.

Categories