How to fix? PHP variable not shows values inside function - php

I want to pass the variable in a function but get an error :
Working Example :
$text_line1 = function (TextToImage $handler) {
$line_first ="Vasim";
$handler->add($line_first)
->position(250, 100)
->font(24, __DIR__ . '/Roboto-Black.ttf')
->color(0, 0, 0);
};
Not Working :
$line_second = $imageMeta[2];
$text_line2 = function (TextToImage $handler) {
$handler->add($line_second)
->position(250, 150)
->font(20, __DIR__ . '/Roboto-Black.ttf')
->color(0, 0, 0);
};

What you are looking for is the "USE" keyword (for anonymous functions, as you are using in your second example). This allows additional variables from the parent scope to be passed into the closure. Its usage can be a little tricky, see the official PHP anonymous function documentation for more information (specifically, see example #3).
$line_second = $imageMeta[2];
$text_line2 = function (TextToImage $handler) use ($line_second) {
$handler->add($line_second)
->position(250, 150)
->font(20, __DIR__ . '/Roboto-Black.ttf')
->color(0, 0, 0);
};

If it is a class then access the variable by adding this keyword. If a normal function and add global in front of it to access a global variable.

Related

PHP Functions returning an array

I am having some issues with my function which returns an array, I decided to try and use an OO approach to my php code and try to make a class with a few static functions since I decided I don't want to access it using an object. In my code, within the same class, I decided to make the following function:
public static function decideCategory($tweets) {
$tweet = $tweets;
if(in_array($tweet, self::$food)) {
echo "\nOur " . $tweet . " is under food\n";
} //if statements of the same nature below as well.
}
Now, this function works in the sense that it does not throw an error where $food is definded as an array at the top. However, originally I simply had $food defined at the top as just a private static variable, and then I had the following function which I passed into the in_array.
public static function getFood()
{
self::$food = array("Wendys", "McDonalds", "Wendy's", "Chic Fil A", "Chic-Fil-a", "Burger", "TGI", "BBQ", "Grilling", "Wine", "Tasty", "Yum", "IHOP", "Pancakes", "Pizza", "Cake"
,"Baking");
return self::$food;
}
However, it would return an error saying that in_array expects an array value for its second argument, but that instead it sees that a null was passed instead. Why is that and how can I use methods to do my comparison rather than the variables themselvs. If this were Java this would be how I would do it, and as such I cannot see why php would have these issues as it appears to follow a similar logic with returns.
Yes it would error because until you call self::getFood() Self::$food is null if you have declared it as
static $food;
update your method as below
public static function decideCategory($tweets)
{
$tweet = $tweets;
$food = self::getFood();
if(in_array($tweet, $food)) {
echo "\nOur " . $tweet . " is under food\n";
} //if statements of the same nature below as well.
}

List all functions used by php call

Is there a way to list all functions used by php call?
For example let's assume that I have a page called example.com/page_to_test.php and this page uses multiple functions within the page itself or from other classes.
What I want is a list of all functions used during the call (at runtime).
You could register a tick function to achieve this
declare(ticks = 1);
$calls = array();
function tracer() {
global $calls;
$bt = debug_backtrace();
if (count($bt) <= 1) return;
$function = $bt[1];
$call = $function['function'];
if (isset($function['class'])) {
$call = $function['class'] . '::' . $call;
}
$calls[$call] = true;
}
register_tick_function('tracer');
After execution of your script, $calls contains each called function in it's keys.
But just do this for debug purpose, as it's very slow.
What can help you is the PHP function
debug_backtrace()
Read more about it at:
http://php.net/manual/en/function.debug-backtrace.php

Access variables from the global scope within a closure

I am well aware that globals are evil and this is an issue I will deal with later. It's not my codebase, but I've been assigned some cleaning up tasks.
Trying to smarten up a codebase, I decided to implement simple routing by using a package known as AltoRouter - I've worked with it before and it has worked fine for my purposes.
Now, the codebase is using a large amount of variables declared in the global scope. Usually, these variables are then fetched by using the globalkeyword. But for some reason, this doesn't work when I'm working inside a closure.
Consider this simple routing example:
<?php
require 'vendor/autoload.php';
$router = new AltoRouter();
$router->map('GET', '/shops/[i:id]', function($id) {
$_GET['shop_id'] = $id;
require 'go_to_shop.php';
});
$match = $router->match();
if( $match && is_callable( $match['target'] ) ) {
call_user_func_array( $match['target'], $match['params'] );
}
This calls my closure that sets a variable and requires a file.
This produces an error:
Fatal error: Call to a member function get() on null in
/vagrant/Core/CampaignHandler.php on line 71
Now, the code being called doing this is the following (line 70-71):
// Inside a method
global $serviceContainer;
$dispatcher = $serviceContainer->get("dispatcher");
The $serviceContainer is being declared by including a file early on:
$serviceContainer = new ServiceContainer();
$serviceContainer->set("dispatcher", new EventDispatcher());
Basically, if I move the contents of the closure outside of the closure, everything works perfectly - but as soon as I'm doing it from inside the closure, all variables accessed via the global scope is empty - and I have no idea as to why.
I've tried using use on the closure, this didn't work either.
I'm mostly looking for an explanation rather than a solution.
Globals are evil for a reason. You get the error because the global is not initialized at the time when function is being called. The mess of globals and requires is the exact issue and you are already trying to deal with it.
There is no problem to use globals in closure per se. This example works perfectly fine:
global.php:
<?php
class Foo {
public function bar() { return 'bar';}
}
$foo = new Foo;
test.php:
<?php
require 'global.php';
$test = function($param) {
global $foo;
echo $param, $foo->bar();
}
call_user_func_array($test, ['baz']);
so php test.php outputs bazbar;
I'm pretty sure that the $serviceContainer variable does not exist in the global scope, but the question leaves that part out.
Can't you pass the container to the anonymous function using a use( $serviceContainer ) statement? That'd be a far cleaner solution then having to rely on globals.
function($id) use( $serviceContainer ) {
$_GET['shop_id'] = $id;
require 'go_to_shop.php';
}
Off-topic: not sure what you're doing with that id variable later on and why you're putting it back into the $_GET variable like that, but please be careful.
Please check the manual for anonymus functions–also known as closures, which in real are objects.
http://php.net/manual/en/functions.anonymous.php
Theses callables have specific functions for extending their scopes.
See: Example #3 Inheriting variables from the parent scope.
$message = 'hello';
// No "use"
$example = function () {
var_dump($message);
};
$example();
// Inherit $message
$example = function () use ($message) {
var_dump($message);
};
$example();
Sure you want to assign a value to the $_GET global var?
$_GET['shop_id'] = $id;
The shop ID in your route you can extract from altorouter parameters. (See documentation.)
$router->map( 'GET', '/', function() { .. }, 'home' );
// assuming current request url = '/'
$match = $router->match();
/*
array(3) {
["target"] => object(Closure)#2 (0) { }
["params"] => array(0) { }
["name"] => 'home'
}
*/
Or if you want to store an ID for a session use $_COOKIES or $_SESSION global variables.

Can non-anonymous functions in PHP using 'use' keyword?

Can non-anonymous functions in PHP using 'use' keyword? Or it is available for anonymous functions only.
Can I write a php file like this
// L.php
// assume $_texts is in this context..
$_language = null;
function L_init($language) use (&$_language)
{
$_language = $language;
}
function L($key) use ($_texts, $_language)
{
$_texts[$_language][$key];
}
So, another file can use it like this
// client.php
require_once 'L.php';
L_init('en');
echo L('GREETING'); // Will output localize string of key 'GREETING'
It is available for anonymous functions, but you can assign it to a variable:
$some_external_var = "World!";
$function = function() use($some_external_var){
echo "Hello ".$some_external_var;
};
Finally you can invoke it with:
call_user_func($function);
or just:
$function();
No you can't.
The code generate syntax errors.

PHP function use variable from outside

function parts($part) {
$structure = 'http://' . $site_url . 'content/';
echo($tructure . $part . '.php');
}
This function uses a variable $site_url that was defined at the top of this page, but this variable is not being passed into the function.
How do we get it to return in the function?
Add second parameter
You need to pass additional parameter to your function:
function parts($site_url, $part) {
$structure = 'http://' . $site_url . 'content/';
echo $structure . $part . '.php';
}
In case of closures
If you'd rather use closures then you can import variable to the current scope (the use keyword):
$parts = function($part) use ($site_url) {
$structure = 'http://' . $site_url . 'content/';
echo $structure . $part . '.php';
};
global - a bad practice
This post is frequently read, so something needs to be clarified about global. Using it is considered a bad practice (refer to this and this).
For the completeness sake here is the solution using global:
function parts($part) {
global $site_url;
$structure = 'http://' . $site_url . 'content/';
echo($structure . $part . '.php');
}
It works because you have to tell interpreter that you want to use a global variable, now it thinks it's a local variable (within your function).
Suggested reading:
Variable scope in PHP
Anonymous functions
Alternatively, you can bring variables in from the outside scope by using closures with the use keyword.
$myVar = "foo";
$myFunction = function($arg1, $arg2) use ($myVar)
{
return $arg1 . $myVar . $arg2;
};
Do not forget that you also can pass these use variables by reference.
The use cases are when you need to change the use'd variable from inside of your callback (e.g. produce the new array of different objects from some source array of objects).
$sourcearray = [ (object) ['a' => 1], (object) ['a' => 2]];
$newarray = [];
array_walk($sourcearray, function ($item) use (&$newarray) {
$newarray[] = (object) ['times2' => $item->a * 2];
});
var_dump($newarray);
Now $newarray will comprise (pseudocode here for brevity) [{times2:2},{times2:4}].
On the contrary, using $newarray with no & modifier would make outer $newarray variable be read-only accessible from within the closure scope. But $newarray within closure scope would be a completelly different newly created variable living only within the closure scope.
Despite both variables' names are the same these would be two different variables. The outer $newarray variable would comprise [] in this case after the code has finishes.
NB: Do not forget that you would better use the immutable data structures (unlike the above) in your common web project. That would account for 99% of the use cases. So the approach above, using mutabliity, is for very seldom kind of "low level" use cases.
I suppose this depends on your architecture and whatever else you may need to consider, but you could also take the object-oriented approach and use a class.
class ClassName {
private $site_url;
function __construct( $url ) {
$this->site_url = $url;
}
public function parts( string $part ) {
echo 'http://' . $this->site_url . 'content/' . $part . '.php';
}
# You could build a bunch of other things here
# too and still have access to $this->site_url.
}
Then you can create and use the object wherever you'd like.
$obj = new ClassName($site_url);
$obj->parts('part_argument');
This could be overkill for what OP was specifically trying to achieve, but it's at least an option I wanted to put on the table for newcomers since nobody mentioned it yet.
The advantage here is scalability and containment. For example, if you find yourself needing to pass the same variables as references to multiple functions for the sake of a common task, that could be an indicator that a class is in order.
I had similar question. Answer: use global. And there are other options.
But if you need named function with usage of outside scope, here what I have:
global $myNamedFunctionWidelyAccessibleCallableWithScope;
$myNamedFunctionWidelyAccessibleCallableWithScope =
function ($argument) use ($part, $orWhatYouWant) {
echo($argument . $part . '.php');
// do something here
return $orWhatYouWant;
};
function myNamedFunctionWidelyAccessible(string $argument)
{
global $myNamedFunctionWidelyAccessibleCallableWithScope;
return $myNamedFunctionWidelyAccessibleCallableWithScope($argument);
}
It is useful for making function myNamedFunctionWidelyAccessible accissible from everywhere, but also binds it with scope. And I deliberately gave very long name, global things are evil :(
Here is documentation with a good example
You can add the below structure
$var1=5;
function sample() use ($var1){echo $var1;}
Just put in the function using GLOBAL keyword:
global $site_url;

Categories