How can I define a superglobal array in PHP?
I know that there is no way to do this. However I thought there might be some "brains" out there knowing about a workaround for it. Specifically I want to have an array on every .php file I have that has the same data. I also want to access it like this:
echo $_HANS["foo"];
or
if( isset($_HANS["foo"]) && !empty( $_HANS["foo"] ) ) // DO
Important for me is that I don't want to have a static class, where I have to access my members like this:
myClass::myVariable;
By now I have something like this, but I guess it's not really efficient:
define( 'HANS', serialize( array( 'FooKey' => 'FooData' ) ));
To access it I have to unserialize it. Storing the data in a variable and THEN I can work with the index-operators.
$_HANS = array();
foreach(unserialize(HANS) as $Key => $Data)
{
$_HANS[$Key] = $Data;
}
echo $_HANS["FooKey"];
There must be a way to skip this whole foreach-stuff in every single file.
EDIT =======================================
Okay, so by now I have this little workaround, which should be a little more efficient, than including a whole new file. However I'm still listening for a better solution :)
I simply put this code above in a global function:
function getData()
{
$_DATA = array();
foreach( unserialize(HANS) as $Key => $Data )
{
$_DATA[$Key] = $Data;
}
return $_DATA;
}
An everything I have to do is to put this line of code in every .php-file:
$_HANS = getData();
The problem about php.ini is the compatibility with companies offering 'webhosting'. They often give you a predefined installation of Apache, PHP, MySQL and Perl (often: LAMP) and don't allow you to edit the php.ini file.
You can declare $myArray at the beginning of the script (you can use a prepend file), and then access it using $GLOBALS['myArray'] from any point after that.
You can use the auto_prepend_file and auto_append_file configuration directive in php.ini, in which you can define marshalling and unmarshalling of whatever global variable. You still will need to do the serialization trick, but you can do it in one place without having to remember to include the handlers.
Related
/* I cant change this part (plugin core files) */
function test123(){
$secret = "hoho"; //i want to get this variable
do_action('custom'); //developer didnt pass any variable here
}
/* I cant change this part (plugin core files) */
add_action('custom',function() use ( $secret ) {
echo $secret; //didn't work
});
test123();
How to get $secret value? because the developer didnt pass any variable when using do_action
You can use like this:
function test123() {
$secret = 'hoho';
do_action( 'custom', $secret );
}
add_action('custom',function( $secret ) {
echo $secret;
});
test123();
Hope this works!
Your variable is out of scope
function test123(){
$secret = "hoho"; //i want to get this variable
do_action('custom'); //developer didnt pass any variable here
} //end of function scoope
add_action('custom',function() use ( $secret ) { //<-- $secret is undefined
echo $secret; //didn't work
});
There are several ways to fix this, but I cant really say how with so little context.
You could move add_action into the function
You could make $secret global etc.
modify the do action call to send it
make it a constant
make it global (keyword)
make it a property of class that maintains it's state (static etc.)
And so on, it depends how dynamic that value needs to be. Maybe that value is a static string, maybe it only exists in your function etc.
How many times you call that function may affect defining it inside, (add/remove action).
You can test this easly:
ini_set('display_errors', 1);
error_reporting(E_ALL);
add_action('custom',function() use ( $secret ) {
echo gettype($secret); //didn't work
});
Expected output
<br />
<b>Notice</b>: Undefined variable: secret in <b>...</b> on line <b>...</b><br />
NULL
UPDATE
I can't change test123()
I sort of figured that, which is why I only gave general solutions. In any case if it's just a plain old local variable within that function, there is no way to "get" its value outside of it short of editing the function in some way. This is a PHP thing (a language thing), not a WordPress thing. It has to do with how scope is handled within the function.
It may be possible to get that data some other way, that depends what it is. For example is it stored in the DB? You may be able to access that way etc... I can't say how to do that without knowing more about what it is.
It's not impossible to edit the original right. Obviously this is not ideal, but it's possible. Some tips are never edit the original. If it's part of a theme try to do it though a child theme. If it's plugin, or child theme doesn't work for it then you can duplicate it and change it's name.
I should mention depending how it's licensed this may be against that license.
You never want to edit the original because if you update the "plugin/theme" you may completely lose your changes. If it's in a copy you can comment around you changes like this:
/* START CUSTOM CODE */
And when you update the original "plugin/theme" you can easily find where your changes where (by searching for that comment text) and work them into the new version of the "plugin/theme". Which may be as simple as coping all the files but the one you changed (if nothing changed in it) etc.
As I said this isn't ideal, but it will work. It just depends how badly you want to implement it and how willing you are to maintain it.
Please see also
https://www.php.net/manual/en/language.variables.scope.php
within user-defined functions a local function scope is introduced. Any variable used inside a function is by default limited to the local function scope
I want to have one class that works with configuration settings. Configuration settings are stored inside config/ directory where I want them to be separated to files. When I call my
Config::gi()->getConfig('config_name')
I want the Config class to be able to access the file config/config_name.cfg.php and return the array (from that file) named exactly the same.
This is because I don't want to read all the configuration data if it's not needed. Also, I'm a bit afraid that setting up configuration inside $GLOBALS variable wouldn't be the best solution. I thought about requiring or including those files and then returning their content, but it also seems a bit unprofessional.
What is the best practice to read the configuration like this? Thank you in advance.
For example:
config/routes.cfg.php
$routes => [
'index' => new Route([
// route config here ...
])
];
and to get the routes array I would execute Config::gi()->getConfig('routes'); from helpers/Config.php class.
I'm not sure I would go this route, I would probably load all configs (most likely from a single file) into the class the first time and go from there. Also you can look at parse_ini_file() if you don't want to write out arrays when they change. But for your case, simply:
public function getConfig($name) {
if(file_exists("config/$name.cfg.php")) {
include("config/$name.cfg.php");
return ${$name}; //this translates to $routes in your example
}
return false;
}
Also, the next logical question might be how to save the config when it changes:
public function setConfig($name, $data) {
file_put_contents("config/$name.cfg.php", "$name = " . var_export($data, true) . ";");
}
$routes = array(/* with some stuff in it */);
Config::gi()->setConfig('routes', $routes);
Here's a pretty obscure one; and I know that I'm reaching here - but I'm trying to find an 'elegant' solution to adding a number of variables to [effectively] the parent scope.
Here's the example:
File 1:
<?
ImportPost();
// Do something with imported variables.
?>
File 2:
<?
function ImportPOST()
{
foreach( $_POST as $Key => $Value )
VariableToParentScope($Key, $Value);
}
?>
So that I would end up with the 'simple' variable names in my first ('DoSomething') method. One thing I find myself doing over and over again is building this small foreach to perform this exact task - but I don't see many other ways to achieve it, other than placing it all in a class - which is generally preferable anyway, but let's say this is in the context of a file that is just some non-OOP PHP.
I've also considered reading the contents of 'File 1', inserting the variables before the rest of the files contents, and then running it - and while this may be the closest thing to a 'proper' implementation there is, I'm still trying to figure out if there is a simpler, or more appropriate one.
Any thoughts?
I.E. - Edit the stack? 0_o
You can use extract to build some variables from an array - here's an example:
function importVars()
{
return array('foo'=>'xyzzy', 'bar'=>'123');
}
function demo()
{
extract(importVars());
echo "foo is $foo\n";
echo "bar is $bar\n";
}
demo();
I'd be wary of doing this with external data such as from $_POST - better to carefully validate what you're bringing in.
You could use $GLOBALS, which essentially would make your variables available in the global scope:
//assuming $_POST = ['foo'=>'bar']
echo $foo; // Notice: Undefined variable
function ImportPOST()
{
foreach( $_POST as $Key => $Value )
$GLOBALS[$key] = $Value;
}
ImportPOST();
echo $foo; // "bar".
However, as you said yourself, it's bad practice to interfere the global scope in that manner.
This seems like a potential security risk to me. I would push all the vars to an array, then pass that around. Or at most, add this array to the global scope. That way, you keep all post data contained in one place, rather than at the same level as all other global variables.
I'm using this code in a views field template (in this case views-view-field--all-members--uid.tpl.php):
<?php
$users_friends = flag_friend_get_friends($user->uid);
$users_friends_ids = array();
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
?>
It basically gets the user ids of friends and puts them in an array so I can check if the field matches any of the user ids.
So my problem is that I don't want to have this within this template (for a few reasons), but if I don't I can't access the array. How can I make this array globally accessible?
Without knowing your "few reasons", I can't say if this is the answer for sure. My own reasons would probably be that I don't want the same code executing a bunch of times, and I'd rather not have the same exact code in multiple places.
I would then create a function with a static variable to hold the friends array.
function mymodule_get_friends_ids() {
// pull in the current global user variable
global $user;
// call up the static variable
static $users_friends_ids;
// return if this static var has already been set
if (is_array($users_friends_ids)) {
return $users_friends_ids;
}
// if we hit here, then this function has not been
// run yet for this page load.
// init array
$users_friends_ids = array();
// if user is anon, no need to go on
if (user_is_anonymous()) {
return $users_friends_ids;
}
// get friends array
$users_friends = flag_friend_get_friends($user->uid);
// build ids array
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
return $users_friends_ids;
}
Now in your templates, you can call mymodule_get_friends_ids() in as many places as you want, and the working code below the first return will only get executed the first time it is called.
Coder1's advice is very good - it keeps you from populating your global variable namespace with a lot of junk. It's probably the most "elegant." It might not be the easiest to use if you are rather new to PHP (which I'm guessing might be the case if it's hard to get your head around returning arrays, but that's ok).
However, if this is really a priority, you probably don't care about having one extra global variable.
I suppose I may be stating the obvious here - but you can, at pretty much any point in execution (provided the information you need has already been generated - e.g., the $user variable has been populated), do this:
$GLOBALS['users_friends_ids'] = /* your code goes here */
Then in your template, you access this by ...
$friendsArray = $GLOBALS['users_friends_ids'];
Or you can simply use the construct
global $user_friends_ids;
when you want to initialize the variable, or access it inside a function or class (which is the case for your template files - they are called inside functions, so you need to globalize or use the $GLOBALS array, which is "automagically" all of the variables active in the global namespace).
The most "logical" place to do this would be inside a module using one of the many hooks available, to execute this code only once. hook_init() might do it for you, if the user object is already loaded at this point (not sure, you'll have to test). But you might not want to figure out making Drupal modules (it's not that difficult).
If you are doing this inside a template (and though it's not good practice, many Drupal site owners with a beginning knowledge of PHP put everything in templates), you'll want to know which template code is being executed when. Node template code tends to be executed before page template code - which is logical, since otherwise the variables for node content in the page template wouldn't be populated.
If you have listings of nodes, they'll be calling this code multiple times, so you'll end up doing something similar to what Coder1 is describing. If you don't want to create your own small module, you could put the function declaration he's written in your theme's template.php file, since it's called only once. You don't want to put function declarations in the tpl.php files, since they are sometimes called more than once (and you aren't allowed to declare functions more than once).
If you have a hard time understanding the function and the return, you can always do something like this in your code (which is very, very inelegant - but it's better to have inelegant code that you do understand, than elegant code that's you don't).
if(!isset($GLOBALS['users_friends_ids'])) {
$GLOBALS['users_friends_ids'] = /* your code here */
}
I've read quite a few posts that are very similar to the question I'm about to ask, but I just wanted to be sure that there wasn't a more sophisticated way to do this. Any feedback is greatly appreciated.
I want to create a mechanism to check whether or not a logged-in user has access to the php script that is currently being called. If so, the script will continue on; if not, the script just fails out using something like die('you have no access').
I came up with two ways of accomplishing this:
(please assume my session stuff is coded/working fine - i.e. I call session_start(), set up the session vars properly and etc)
Define a global variable first, then check the global variable in a required header file. For example:
Content of current_executing_script.php:
// the role the logged in user must have to continue on
$roleNeedToAccessThisFile = 'r';
require 'checkRole.php''
Content of checkRole.php:
if ($_SESSION['user_role'] != $roleNeedToAccessThisFile) die('no access for you');
Define a function within the header file and call the function immediately after including/requiring it:
Content of checkRole.php:
function checkRole($roleTheUserNeedsToAccessTheFile) {
return ($_SESSION['user_role'] == $roleTheUserNeedsToAccessTheFile);
}
Content of current_executing_script.php:
require 'checkRole.php';
checkRole('r') or die('no access for you');
I'm wondering if there is a way to basically just pass a parameter to checkRole.php as part of the include or require construct?
Thanks in advance.
There isn't a way to pass parameters to include or require.
However the code that is included joins the program flow at the point where you include it, so it will inherit any variables that are in scope. So for example if you set $myflag=true immediately before the include, your included code will be able to check what $myflag is set to.
That said, I wouldn't suggest using that technique. Far better for your include file to contain functions (or a class) rather than code that gets run straight off. If you've included a file containing functions then you can call your functions with whatever parameters you want at any point in your program. It's much more flexible, and generally a better programming technique.
Hope that helps.
This could be a useful workaround.
Register a function in say functions.php:
function get_template_partial($relative_include_path, $scoped_parameters)
{
$base_partial_directory = get_template_directory() . '/partials/';
return include $base_partial_directory . $relative_include_path;
}
Use the $scoped_parameters in the partial /partials/role-check.php:
$args = [
'id' => $scoped_parameters['user_id']
];
// A few moments later...
return [
'role_required' => 'admin'
];
Altogether now...
$partial_return_data = get_template_partial('role-check.php', [
'user_id' => 328
]);
echo $partial_return_data['role_required']; // admin
The only thing I can remember with this is if you're using an IDE it might complain that $scoped_parameters is undefined but it's not a third world issue I suppose.
You could have the required file return an anonymous function, and then call it immediately after.
//required.php
$test = function($param)
{
//do stuff
}
return $test
//main.php
$testing = require 'required.php';
$testing($arg);
In the past, many people have disagreed with this approach. But I think it is a matter of opinion.
You can't pass _GET or _POST param via a require() or include() , but you can you first set a _SESSION key/value and pull it on the other side.