This might be a very dumb question but it still bugs me. I tend to use this:
$variable = $someObject->getSomeValue();
for ($i = 0; $i < $x; $i++) {
performSomeFunction($variable);
}
I have seen people do the following & some of my co-workers are arguing with me that there is no difference in performance if I use function calls within a loop & that it will save 1 line of code.
for ($i = 0; $i < $x; $i++) {
performSomeFunction($someObject->getSomeValue());
}
Now for $x = 10 this might not have impact on performance but what if $x = 10000 ? Which one is the preferred way or best practice in PHP and in Programming general?
Example of function getSomeValue
// just a getter method for the class
function getSomeValue() {
return $this->userFirstName;
}
Highly depends on your function. For example this
function() {
return 2;
}
It won't matter.
For this:
function() {
$pdo->query('SELECT ....');
// more db stuff
return $someDbStuff;
}
It will matter extremely!
Depends on what you do on $someObject->getSomeValue();. If just returns a variable, it doesn't have any impact on performance, if, on the other hand, you are retrieving the data from a database, its very important to avoid it.
However, its always a good policy to avoid unnecessary iterations and do like this
$variable = $someObject->getSomeValue();
for ($i = 0; $i < $x; $i++) {
performSomeFunction($variable);
}
Yeah, sure there's an impact in the performance.
If you are about to use the same value over iterated loops, why would you go get it every time?
It's better getting it before the loop (if there's no chance of changing this value while in the loop) and then reusing it.
Imagine this getSomeValue() needs to access a database or a webservice, would you rather do it 1 time or $x times for the same effect?
Related
How can I let a user (e.g. admin), by text input, choose which function to use?
I have really tried to think of a solution for this, and I really don't want to use eval, I can't even use it anyways because it is disabled (which is good), but I need the user to be able to specify what function the program needs to perform for a couple of times.
It is a general function that allows you to choose which function you want to perform, and then performs the function a lot of times.
Let me give an example that should work: (but I don't want to do this, because it uses eval, and eval is also disabled)
function generate_random_integer($a, $b) {
...
}
function rinse_and_repeat($array, $count) {
$function_name = $array[0];
$params = $array[1];
$param_string = implode(",", $params);
$query= '$function_name($param_string);';
$total = 0;
for($i = 0; $i < $count; $i++) {
$value = eval($query);
if($verbose) { print($value); }
$total += $value;
}
$ratio = $total/$count;
return($total);
}
$input = array("generate_random_integer", array(1, 10));
$total = rinse_and_repeat($input, 100);
Don't stare blind on the "generate_random_integer", I know I can do that with other functions, but I want a general solution for letting the user choose which function to perform.
How do I make something similar to this, without using eval?
Can you only do this with eval or similar functions?
If you are using OOPs, you can probably make use of strategy design pattern, which is a good practice. Using this pattern you can create object of a class based on user input
Create different class for each user input, so that you can create object of that particular class. All methods that depend on user input can go into that class.
https://refactoring.guru/design-patterns/strategy/php/example
In a PHP framework which provides hookpoints that are implemented using eval() I am trying to interrupt or continue a loop from within an eval() call.
This is what I am trying
The framework loops like
...
for( $i = 0; $i < 10; $i++ ) {
// framweork code here ...
eval( $plugin_code );
// framweork code here ...
}
...
$plugin_code contains PHP-code - in this sample case
if( $i == 5 ) {
continue;
}
It results in this error
PHP Fatal error: 'continue' not in the 'loop' or 'switch' context
If it is true that eval() only evaluates expressions and can NOT evaluate statements - then how can I implement the continue / break statements inside an eval()?
Leaving aside the mechanics of eval and continue for a moment, I think there is a more fundamental point to make: when writing code that "plugs in" to another system, you can only do what that system allows you to do.
If the hook system simply executes the code you give it (whether via eval, or a callback function, or any other mechanism), you cannot use it to control the flow of loops etc in the main framework code.
If the framework wanted you to do that, it would have to provide a mechanism for your plugin to signal back to the framework what you want it to do - you might register the plugin in a particular way, return a particular value from the callback, set a particular variable, etc.
If you don't want to directly modify the framework, your only option is to request such a feature from the framework's author.
You can't use a statement like continue or break in eval() to affect an outside loop.
I suggest using a variable.
$plugin_code = 'if( $i == 5 ) {
$continue = true;
}';
$continue = false;
for( $i = 0; $i < 10; $i++ ) {
eval( $plugin_code );
if ($continue) {
continue;
}
// other code
}
If you also want to skip the rest of the plugin code, it should put that code in an else block.
$plugin_code = 'if( $i == 5 ) {
$continue = true;
} else {
// other code
}';
IMHO, this whole thing smells fishy. The plugin is dependent on the specific variable being used for the loop, which is quite fragile.
Keywords like continue, break and return which affect the control-flow of the program cannot be used directly inside eval to achieve the result you want. eval is a function, and a function cannot change the control-flow of the code which calls it, except by throwing an exception.
Since continue simply means "skip to the next iteration of the loop", and this is equivalent to "don't execute the rest of the code in this block", you could rewrite your code to make the rest of the block conditional on the if statement instead. If the code looks like
for( $i = 0; $i < 10; $i++ ) {
if( $i == 5 ) {
continue;
}
// do more things
}
then this can trivially be rewritten as
for( $i = 0; $i < 10; $i++ ) {
if( $i != 5 ) {
// do more things
}
}
and this is now in a form which can be eval'd:
// your code
$plugin_code = 'if( $i = 5 ) {
// do more things
}';
// framework code
for( $i = 0; $i < 10; $i++ ) {
eval($plugin_code);
}
However this still only affects the control-flow of the code you're passing into the framework. It's not possible to change the control-flow of the framework code itself.
I have been reading PHP manual pages, but I am obviously reading the wrong ones. I ran a few simple tests to see which means of obtaining a variable was faster: using global, declaring the variable inside the function, or using a declared constant.
Summary:
Declaring the variable (e.g., $keyspace = 012...;) was fastest.
Using global (e.g., global $keyspace;).
Defining a constant (e.g., define('keyspace', '01234...'); was slowest.
Question: Why is using global or define slower than declaring a variable in PHP?
(1) Variable defined outside function, function uses global
$keyspace = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
function buildSKU(){
global $keyspace;
$sku = '';
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < 8; ++$i) {
$sku .= $keyspace[random_int(0, $max)];
}
return $sku;
}
(2) Variable defined inside function
function buildSKU(){
$keyspace = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$sku = '';
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < 8; ++$i) {
$sku .= $keyspace[random_int(0, $max)];
}
return $sku;
}
(3) Variable defined as a constant
define('keyspace', '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ');
function buildSKU(){
$sku = '';
$max = mb_strlen(keyspace, '8bit') - 1;
for ($i = 0; $i < 8; ++$i) {
$sku .= keyspace[random_int(0, $max)];
}
return $sku;
}
My test bed:
<?php
$start = microtime(true);
//Put (1) or (2) here...
for($i=0; $i<10000; $i++){ buildSKU(); }
$end = microtime(true) - $start;
echo "\n\nTime: ".$end."\nMemory:".memory_get_peak_usage(true)."\n\n";
Your title is a bit misleading. A function variable is not being 'declared' over and over, it was declared once when you wrote the function code. You also focused on an apples to oranges comparison.
With the function variable example, the scope of the variable is entirely different. A local variable declared inside a function ceases to exist (at least from the scope perspective) once the function completes. It's also being initialized, unlike the global example where the state of the variable at the start of the function is completely unknown.
You spent a lot of time looking at micro optimization and a meaningless benchmark, when the answer is much simpler. It is never better to use the global keyword to inject a variable into function scope.
You have parameters for doing that which can be passed by reference or value, but you did not evaluate those options, although I have to reiterate that in my opinion you aren't really going to find out anything interesting.
In most languages that create a compiled program, function variables are allocated on the stack. Once the function completes, that area of memory is popped off the stack and discarded. PHP however, has a a variable naming and memory allocation scheme that is shared across all variables and objects. You can search for information on 'php zval' and php internals, and find out more about the way variables are allocated, reference counted, and associated with names via symbol tables.
The important point to make here, is that the variable allocation occurs in the same way regardless of the type of variable it is, so any expectation about performance purely of variable allocation syntax is unlikely to provide any meaningful differences.
PHP makes all sorts of decisions in regards to when it needs to make a new zval or simply point multiple symbols at the same one, and that is meant to be transparent to you.
I think the main issue with global is the dependency issue, where your entire code base would be depended on that global variable and its existence, as your code grows , it is very hard to keep track and trouble shoot. Even a name change requires you change everywhere in your code.
in your code if key doesn't change maybe you should consider using constant.
Always use local variable unless it is absolutely needed and there is no other way around.
I have an object with lots of properties. Some of the properties have their names start with the same string of text (in my example to come "bullet"), followed by an integer.
I can fetch the property values as follows:
echo $objectName->bullet1;
echo $objectName->bullet2;
echo $objectName->bullet3;
and so on.
I'm trying to write a for loop to get the first 20 of these, and at the moment it looks a bit like:
for ($i = 1; $i <= 20; $i++){
if ($objectName->bullet$i){
echo $objectName->bullet$i;
}
}
But this isn't working. I know I could write something like
$bulletsArray[1] = $objectName->bullet1;
$bulletsArray[2] = $objectName->bullet2;
$bulletsArray[3] = $objectName->bullet3;
all the way through to 20, then put a for loop on that, but I'm sure there must be a cleaner way. Can someone point me in the right direction?
This is how you can do it:
for ($i = 1; $i <= 20; $i++){
$propertyName = "bullet$i";
if ($objectName->$propertyName){
echo $info->$propertyName;
}
}
Though I think using an array instead of the object would be a better solution.
$var = 'myVariable';
$value = $object->$var;
is the correct syntax for accessing a field by name in PHP.
In your case it would look something like this:
for ($i = 1; $i <= 20; $i++)
{
$var = 'bullet'.$i;
if ($objectName->$var)
{
echo $info->$var;
}
}
Both previous answers have the "try it, if it doesn't work, move on" and are working for a very specific situation. Let me give you a more generic approach, which, sadly, requires PHP 5.
A bit about Reflection
Reflection allows you to reflect on an object or class to extract useful information about it. In particular, you can use Reflection to get all the properties set in a class, whether static, at run-time, or generated on the go.
To do this, start by initiating your Reflection object (assuming your class object is $object) as follows:
$refObj = new ReflectionObject($object);
This will now give you a reflection interface. Notice the useful ReflectionObject::getProperties() method - it allows you to get all properties set in a class (and you can filter by public, protected, private etc... if needed). We'll use exactly this:
$yourNewArray = array();
$PropertyArray = $refObj->getProperties();
$pCount = count($PropertyArray);
for ($i = 0; $i < $pCount; $i++) {
$yourNewArray[$PropertyArray[$i]->getName()] = $PropertyArray[$i]->getValue($object);
}
Done. Completely generic, works anywhere.
in my system, which doesn't allow me to do
$myPropertyValue = $object->$property;
I still can get to the value of the 'variable' property name with the function below; you can set $property without php complaining about syntax or throwing errors.
<?php
class MyClass{
public function getProperty($propertyName){
$props=get_object_vars($this);
if (array_key_exists($propertyName,$props)){
return $props[$propertyName];
}else{
return FALSE;
}
}
}
?>
I have this function that I wrote that is abysmally slow since php does not handle recursion well. I am trying to convert it to a while loop, but am having trouble wrapping my head around how to do it.
Can anyone give me some tips?
public function findRoute($curLoc, $distanceSoFar, $expectedValue) {
$this->locationsVisited[$curLoc] = true;
$expectedValue += $this->locationsArray[$curLoc]*$distanceSoFar;
$at_end = true;
for($i = 1; $i < $this->numLocations; $i++) {
if($this->locationsVisited[$i] == false) {
$at_end = false;
if($expectedValue < $this->bestEV)
$this->findRoute($i, $distanceSoFar + $this->distanceArray[$curLoc][$i], $expectedValue);
}
}
$this->locationsVisited[$curLoc] = false;
if($at_end) {
if($expectedValue < $this->bestEV) {
$this->bestEV = $expectedValue;
}
}
}
I'm not going to convert your code, but you can convert a recusive function into an iterative one by creating a stack:
$stack= array();
And instead of invoking $this->findroute(), push your parameters onto this stack:
$stack[] = array($i, $distanceSoFar + $this->distanceArray[$curLoc][$i], $expectedValue);
Now surround basically everything in your function into a while loop draining the stack after having primed it:
while ($stack) {
// Do stuff you already do in your function here
You can convert a recursive function into an iterative function by using a stack to store the current state. Look into array_push() and array_pop().
At a glance I don't think recursion is your problem, yes it's slow in PHP, but It looks like your going over values more than you need to, putting the values in a stack, or several stacks and handling them, may be nice.
custom sort functions have always helped me with problems of this sort.
function sort_by_visited($x,$y)
{
return ($this->locationsVisited[$x] > $this->locationsVisited[$y]) ? -1 : 1;
}
uasort($locationsVisited,'sort_by_visited');
This will prioritize all not visited locations at the top of the stack.
This looks like your trying to find the optimal route for traversal of a series of nodes in a graph.
I'm guessing that you've not studied Computer Science as the "Travelling Salesman" problem is an archetype of Artificial Intelligence. Of course, as such, it has its own Wikipedia page:
http://en.wikipedia.org/wiki/Travelling_salesman_problem
Sorry - but just swapping from a recursive to an iterative function isn't going to make it go any faster ("php does not handle recursion well." - can you provide reference for this assertion). If you need a faster solution then you'll need to look at non-exhaustive/fuzzy methods.
C.