Multiple procedure assignment for self variable in one line - php

Is there any way a variable can be assigned from multiple procedures in one line?
For example:
$class_splits = explode("\\", $class_name);
$short_class_name = $class_splits[count($class_splits) - 1] ?? null;
Translated to this pseudo code:
$short_class_name = explode("\\", $class_name) => prev_result(count(prev_result) -1);
I don't have big expectations on this as I know it looks too "high-level" but not sure if newer versions of PHP can handle this.
Thanks.

You can use an assignment as an expression, then refer to the variable that was assigned later in the containing expression.
$short_class_name = ($class_splits = explode("\\", $class_name))[count($class_splits) - 1] ?? null;
That said, I don't recommend coding like this. If the goal was to avoid creating another variable, it doesn't succeed at that. It just makes the whole thing more complicated and confusing.

I believe you have an "X/Y Problem": your actual requirement seems to be "how to split a string and return just the last element", but you've got stuck thinking about a particular solution to that.
As such, we can look at the answers to "How to get the last element of an array without deleting it?" To make it a one-line statement, we need something that a) does not require an argument by reference, and b) does not require the array to be mentioned twice.
A good candidate looks like array_slice, which can return a single-element array with just the last element, from which we can then extract the string with [0]:
$short_class_name = array_slice(explode("\\", $class_name), -1)[0];
Since we no longer need to call count(), we can avoid the problem of needing the same intermediate value in two places.
Whether the result is actually more readable than using two lines of code is a matter of taste - remember that a program is as much for human use as for machine use.

Related

php - Is it possible to use result of equation stored in a variable directly?

For example
$var = '10/2';
Is there a way for me to output the value 5 from that easily?
So something like this:
$foo = ($var) + 5;
I want $foo to have a value of 10?
Currently, the best way I know is to explode $var and then divide $var[0] by $var[1]. Is there a quicker way?
Another way of asking; Is there a way to tell the system to treat '10/2' as an equation instead of a string?
Could be you can use a solution like this
$foo = eval('return '.$var +5 .';');
print $foo;
eval require a line of code .. so you could build a valid code line
eval() to either assign in place or return:
eval("\$foo = ($var) + 5;");
$foo = eval("return ($var) + 5;");
First things first, EVAL IS HAZARDOUS AND SHOULD NEVER BE USED UNLESS YOU KNOW WHAT YOU'RE DOING! As an addendum to this, you don't know what you're doing. No matter how experienced you are as a programmer, when it comes to eval just assume you don't know what you're doing. Believe me, in the long run your sanity will thank you.
As for your problem, you're basically asking how to write an equation parser. Writing a full blown one that can handle all cases of valid input (and reliably identify invalid input) is a much bigger job than you might at first think, so if you really do need to parse string equations it may be better to look for a library that will do it for you because the chances are whoever wrote the library thought of a lot of stuff that you didn't, such as handling operator precedence and how parenthesis can modify it, how to pass strings in scientific notation, etc.
One of your comments suggests using PHP Math Parser. I've never personally used it, but I know the author by reputation well enough to believe it's a reliable library.
If your use case is always going to be as simple as your example then you can simply split the string and process the resulting fragments.
$parts = explode ("/", $var);
$foo = $parts[0] / $parts[1];

Efficient if statement / for loop

2 short questions based on trying to make my code more efficient (I think my ultimate quest is to make my entire (fairly complex) website based on some sort of MVC framework, but not being a professional programmer, I think that's going to be a long and steep learning curve..)
In this code, is there a way to merge the if statement and for loop, to avoid the nesting:
if($fileatt['name']!=null)
{
$attachedFiles = "You uploaded the following file(s)\n";
for($i=0;$i<count($docNames);$i++)
{
$attachedFiles = $attachedFiles. " - " . $docNames[$i] . "\n";
}
}
At the moment, I do the fairly standard thing of splitting my $_POST array from a form submission, 'clean' the contents and store the elements in individual variables:
$name = cleanInput($_POST['name']);
$phone = cleanInput($_POST['phone']);
$message = cleanInput($_POST['message']);
...
(where cleanInput() contains striptags() and mysql_real_escape_string())
I had thought that keeping all the information in an array might my code more efficient, but is there a way to apply a function to all (or selected) elements of an array? For example, in R, this is what the apply() function does.
Alternatively, given that all my variables have the same name as in the $_POST array, is there a way to generate all the variables dynamically in a foreach loop? (I know the standard answer when people ask if they can dynamically generate variables is to use a hashmap or similar, but I was interested to see if there's a technique I've missed)
You can use extract and combine it with array_map
extract(array_map('cleanInput', $_POST), EXTR_SKIP);
echo $name; // outputs name
Be warned that $_POST could be anything and user can then submit anything to your server and it becomes a variable in your code, thus if you have things like
if(empty($varName)) { } // assumes $varName is empty initially
Could easily bypassed by user submitting $_POST['varName'] = 1
To avoid mishaps like this, you can have a whitelist of array and filter out only those you need:
$whitelist = array('name', 'phone', 'message');
$fields = array();
foreach($_POST as $k => $v) {
if(in_array($k, $whitelist)) $fields[$k] = $v;
}
extract(array_map('cleanInput', $fields));
1) To the first question, how to merge the if and the for loop:
Why would you want to merge this, it will only make the code more difficult to read. If your code requires an if and afterwards a for loop, then show this fact, there is nothing bad with that. If you want to make the code more readable, then you can write a function, with a fitting name, e.g. listAttachedFiles().
2) To the question about cleaning the user input:
There is a difference between input validation and escaping. It's a good thing to validate the input, e.g. if you expect a number, then only accept numbers as input. But escaping should not be done until you know the target system. So leave the input as it is and before writing to the db use the mysql_real_escape_string() function, before writing to an HTML page use the function htmlspecialchars().
Combining escape functions before needed, can lead to invalid data. It can become impossible to give it out correctly, on a certain target system.
Personally I think that the performance cost of using an "If" statement is worth the benefit of having easily readable code. Also you have to be sure that you actually use fewer cycles by combining, if there is such a way.
I'm not sure I follow your second question, but have you looked at extract() and array_walk() yet?
Point 1 is premature optimization. And you want get any better performance / readability by doing so. (similar for using arrays for everything).
Point 2 - AaaarrgghhH! You should only change the representation of data at the point where it leaves PHP, using a method approporiate to the destination - not where it arrives in PHP.
To make your for loop more efficient don't use Count() within the condition of your loops.
It's the first thing they teach in school. As the For loops are reevaluating the conditions at each iterations.
$nbOfDocs = count($docNames); //will be much faster
for($i=0;$i<$nbOfDocs;$i++)
{
$attachedFiles = $attachedFiles. " - " . $docNames[$i] . "\n";
}

PHP Passing by reference

Lets assume the following:
private $array = array(/*really big multi-dimensional array*/);
public function &func1($specific_large_sub_array_key)
{
return $this->array[$specific_large_sub_array_key]
}
public function func2()
{
$specificArray = &$this->func1(1);
$this->func3($specificArray);
}
public function func3($specificArray)
{
/* do stuff here*/
}
My question is this:
If func3 does not specify that $specificArray is not passed by reference to it, does PHP make a copy of $specificArray when it calls func3 inside of func2? Or does PHP keep the reference and propagate it automatically?
i.e. Will this...
public function func3($specificArray)
{
unset($specificArray[234]);
}
...affect $array?
Thank you
Note, this example is extremely simplified.
PHP is pretty intelligent as to how it deals with variables and copies.
Take the following example:
// Allocate one variable with content 'Hello'
$var = 'Hello';
At this point, the Zend Engine has a representation of your string variable with the content, Hello.
Now if you do this:
$varCopy = $var;
You have 2 independent variables ($var and $varCopy), but since their contents are the same, the content only exists in one place in memory (basically a true copy hasn't been made yet). At this point, the two variables reference the same value (Hello) in a symbol table. It will only copy the contents once one of the two variables is modified. This same logic works for 2 copies to any number of copies.
Put simply, PHP is smart enough not to copy the value of the variable or array when it isn't necessary to make a copy.
You can learn more about this on the Reference Counting Basics page on the PHP manual. They even give an example specific to arrays towards the end.
A useful function is memory_get_usage which can show you how much memory PHP is using. You can use this to track the fact that the memory usage will change very little as you pass multiple copies of your array around. This can help prove the point outlined in the reference counting basics section of the manual.
You don't need to know all the details about how it works, but do be aware that PHP is smart in how it creates and manages references.
EDIT:
To answer your actual question directly, no, in func3 PHP will not make a copy of the array even if you don't pass it by reference. It will use references as illustrated in the reference counting basics section, so you can pass it by value without any concern.
If you call unset however, the value you unset will only be removed from the local copy of the array, so it ultimately isn't removed from the source array unless you pass it by reference to the function. But passing it by value does not create a whole new copy of the entire gigantic array. Even removing one value from the copy doesn't create a whole new copy minus the entry you removed (you just have a second array with all identical references to the first, but it is missing the one reference to the removed entry).
Can't do multiline comments, so as an answer:
return &$this->array[$specific_large_sub_array_key]
^
But to also give you an answer to your question:
i.e. Will this... [...] ...affect $array?
Plain and simple: No. Reason: It's a different variable, not an alias (reference).

Easiest and most efficient way to get data from URL using php?

Solution?
Apparently there isn't a faster way, I'm okay with that.
I am just learning php and I am trying to figure out some good tips and tricks so I don't get into a bad habit and waste time.
I am passing in values into a php script. I am using $_GET so the URL looks like this:
/poll_results.php?Sports=tennis&cat=Sports&question=Pick+your+favorite+sports
Now I know how to accept those values and place them into variables like so:
$sports = $_GET['Sports'];
$cat = $_GET['cat'];
$question = $_GET['question'];
Super simple yet if I am passing 5 - 6 things it can get bothersome and I don't like typing things out for every single variable, that's the only reason. I know there is a better way of doing this. I have tried list($var, $var, $var) = $_GET but that doesn't work with an associative array just indexed ones (i think).
I also tried variable variables like so:
foreach($_GET as $value) {
$$values = $value;
echo $$values;
}
But that gave me a Notice: Undefined variable: values in poll_results.php on line 14. Line 14 is the $$values = $value. I don't know if that's a big deal or not... but I'm not turning off error reporting as I am still in the process of building the script. It does do what I want it to do though...
Any answers will be copied and pasted into my question so the next person knows :D
Thanks guys!
Your second bit of code is wrong. It ought to be like
foreach ($_GET as $key => $value) {
$$key = $value;
}
if i understand your intent. However, you're basically reinventing register_globals, which....eh. That'll get ya hacked.
If you have certain variables you want to get, you could do like
foreach (array('Sports', 'cat', 'question') as $key)
{
$$key = $_GET[$key];
}
which is less likely to overwrite some important variable (whether by accident or because someone was messing around with URLs).
Use parse_url() to extract the query string from a URL you've got in a string, then parse_str() to extract the individual arguments of the query string.
If you want to pollute your script with the contents of the superglobals, then you can use extract(). however, be aware that this is basically replicating the hideous monstrosity known as "register_globals", and opens all kinds of security vulnerabilities.
For instant, what if one of the original query arguments was _GET=haha. You've now trashed the $_GET superglobal by overwriting it via extract().
I am just learning php and I am trying to figure out some good tips and tricks so I don't get into a bad habit and waste time.
If I am passing 5 - 6 things it can get bothersome and I don't like typing things out for every single variable, that's the only reason.
What you are trying to do will, unless curbed, become a bad habit and even before then is a waste of time.
Type out the variables: your digits like exercise and your brain can take it easy when it doesn't have to figure out which variables are available (or not, or maybe; which would be the case when you use variable variables).
You can use
foreach($_GET as $key => $value)
To preserve the key and value associativity.
Variable variables (the $$value) are a bad idea. With your loop above say you had a variable named $password that is already defined from some other source. Now I can send $_GET['password'] and overwrite your variable! All sorts of nastiness can result from this. It's the same reason why PHP abandoned register_globals which essentially does the same thing.
My advice: use $_POST when possible. It keeps your URLs much cleaner for one thing. Secondly there's no real reason to assign the array to variables anyway, just use them where you need them in the program.
One good reason for this, especially in a large program, is that you'll instantly know where they came from, and that their data should not be trusted.

Problem with PHP Array

Why is it not possible to do something equivalent to this in PHP:
(Array(0))[0];
This is just for sake of argument, but it seems strange it does not allow access of anonymous objects. I would have to do something like the following:
$array = Array(0);
$array[0];
Any ideas why this is the behavior of PHP?
I read something somewhat detailed about this once and I regret not bookmarking it because it was quite insightful. However, it's something along the lines of
"Because the array does not exist in memory until the current statement (line) executes in full (a semicolon is reached)"
So, basically, you're only defining the array - it's not actually created and readable/accessible until the next line.
I hope this somewhat accurately sums up what I only vaguely remember reading many months ago.
This language feature hasn’t been inplemented yet but will come in PHP 6.
I guess the short answer is: nobody has coded it yet. I've used (and loved) that syntax in both Python and Javascript, but still we wait for PHP.
The main reason is because unlike some languages like Python and JavaScript, Array() (or in fact array()) is not an object, but an language construct which creates an inbuilt data type.
Inbuilt datatypes themselves aren't objects either, and the array() construct doesn't return a reference to the "object" but the actual value itself when can then be assigned to a variable.

Categories