Require/Include and Undefined Variables in PHP - php

SOLVED: The error had nothing to do with require or include. It was completely unrelated to the question. Sorry about that. :(
I thought I had an understanding of require/include until now. I have a file named file_one that has something like this, $user_data = return_user_data_as_array(). My second file file_two, calls $user_data. Now, when I do a include 'file_two.php' into the file_one page after the functions and variables have been called, the page returns with undefined variable user_data. I thought that if you include/require a file into your php code it would pick up any variables written in the original file? How would I fix this?
Edit: I also want to mention that although the undefined variable error is popping up on my screen, the "undefined" variables are correctly echoed out.
File One
//this require_once holds the function user_data()
require_once 'core/init.php';
$user_id = 1;
$profile_data = user_data($mysqli, $user_id);
//this calls file two
require_once 'file_two.php';
File Two or file_two.php
echo $profile_data['full_name'];

The key thing here is to have your include before not after the function call. Also just include the function and then call it in file two.

I think you must have an error elsewhere on the page. If you're defining the variable outside of a function or class and you're including the file that uses it after it's been defined it should work fine:
file_one.php
<?php
function return_user_data_as_array(){
return array('name'=>'BenD');
}
$user_data = return_user_data_as_array();
include('file_two.php');
?>
file_two.php
<?php
print_r( $user_data );
?>
Result:
Array
(
[name] => BenD
)
This should all work fine. Your error is probably arising elsewhere (for instance, you might be calling $user_data from inside a function without specifying global $user_data, or you're calling $user_data somewhere in file_one.php accidentally?)
EDIT
Now that you've shown some code, I imagine that the problem is that user_data() isn't returning an array that includes the full_name key. Try print_r($profile_data) to see what the array looks like. I'm guessing that the problem lies in what's being returned from user_data() (if anything! make sure it includes a return $x clause in there! I've spent a lot of time trying to figure out a logical error when the only problem was that my function didn't return anything)

The answer had nothing to do with the problem in the question. The code in the question is correct.

Related

How can I check which variables aren't set in an included file, prior to interpretation, or should I?

I have Googled for the past couple hours trying to figure out how to do this. I just want to be clear that my issue is not this issue or that issue, because I am not trying to check inside the script if the variables are set. I am trying to check outside it, to see if they're set / passed to the included file before they're interpreted, or at least meaningfully interpreted to the point where an error is thrown. Let me explain.
A little Background
I am creating a utility package for internal usage at the company I work for. I have chosen to render templates one of two ways: including them or outputting the rendered string.
public function render($context = array()) {
do_action(self::TAG_CLASS_NAME.'_render_view', $this, $context);
if ( empty( $this->html ) ) {
ob_start();
$this->checkContext($context);
extract( $context );
require_once $this->getFullPath();
$renderedView = ob_get_contents();
ob_end_clean();
$this->html = $renderedView;
return $renderedView;
} else {
return $this->html;
}
}
public function includeView($context = array()) {
do_action(self::TAG_CLASS_NAME.'_include_view', $this, $context);
extract( $context );
include $this->getFullPath();
}
The problem
Inside of the render method, I start some output buffering. This is so I can have the interpreter evaluate the code and output the HTML as a string (without taking the eval() hit. Inside my unit tests, I experiemented with what would happen if I left out a context that was inside the template itself. For example: If I have a context array that looks like:
$context = array(
'message' => 'Morning'
);
And an associated template that looks like this:
<?php echo "Hello ".$name."! Good ".$message; ?>
Or this
<p>Hello <?php echo $name; ?>! Good <?php echo $message; ?></p>
Doesn't matter how it's formatted, as long as the context vars are passed to it correctly. Anyway, leaving out the $name in the context will result in a "Undefined variable: $name" E_NOTICE message. Which makes sense. How do you 'capture' that undefined variable before it creates the notice?
I have tried to use:
$rh = fopen($this->getFullPath(), 'r');
$contents = fread($rh, filesize($this->getFullPath()));
fclose($rh);
Where $contents outputs:
"<?php echo sprintf("Hello %s, Good %s.", $name, $greeting); ?>"
The next logical step (for me anyway, thus the question) is to extract the vars in that string. So I briefly started down the road of creating a regex to match on that string and capture the variables, but ended up on here, because I felt like I was duplicating work. I mean, the PHP interpreter already does this effectively, so there must be a way to utilize the built-in functionality. Maybe?
All this to say, I want to do something similar to this psuedo code:
protected function checkContext($context) {
require $filename;
$availVars = get_defined_vars()
if ( $availVars !== $context ) {
setUnDefinedVar = null
}
}
Having said that, this may not even be the right way to do it, but what is? Do I let the interpreter fail on an undefined variable upon inclusion of the file? If I let it fail, am I exposing myself to any security vulnerabilities? Note: I am not setting any variables in templates via $_GET or $_POST.
Any answers are much appreciated. Thank you ahead of time.
I recommend using getters and setters within your class. There may be a better solution but this is how I do it. Since you're trying to access variables in the global scope you would add the following method to the class calling the included file:
public function __get($variable)
{
if (array_key_exists( $variable, $GLOBALS ))
return $GLOBALS[$variable];
return null;
}
So now in your included file you would access variables by using the
$this->{$variableName}
In your specific case, it would look like...
<?php echo "Hello ".$this->name."! Good ".$this->message; ?>
However please note, if the variable requested is defined in the scope of the calling class then that particular member variable will be returned. Not one defined in the global scope.
A better explanation of this overloading operator may be found here PHP Magic Methods

Dynamically include variables php [duplicate]

This question already has answers here:
Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?
(3 answers)
Closed 9 years ago.
I am trying to get figure this out and haven't been able to. I'm trying to create a function that will include different config files into the script when needed. I want to store all the variables in arrays and then use a function to include them.
Example
Config.php
$array = array(
'var1' => 'something',
'var2' => 'something else'
);
uses.php
class uses{
public static function file($directory, $file){
if(is_dir($directory))
{
if(is_file($directory.$file))
{
include $directory.$file;
}
else
{
echo "File Not Found $directory$file";
}
}
else
{
echo 'Dir Not Found';
}
}
}
index.php after I've included uses the file
uses::file(Config.php);
print_r($array);
I know if you include a file inside a function they won't reach past the scope of the function. This would be loaded in by an auto loader so I would be able to use it anywhere inside my script.
Thanks in advance, if you need any more information please let me know.
It appears to me you may be going about this the wrong way. But first off the problems with the code you presented. Your code appears to be asking for two parameters but you are only passing in one. This will make your is_dir / is_file calls always fail because both of the conditions will never be true at the same time so your file isn't include.
Also you don't appear to be assigning the returned value to anything that has a lifetime greater then that of run time of your static function so even if the file was included your config variable would end up being thrown away.
To clean up your existing code you could do something along these lines.
<?php
class Config {
static public $config;
public static function load($path, $file){
if (file_exists($path.$file) && is_file($path.$file)){
self::$config = include ($path.file);
}
}
}
Then you would change your included file to return the data instead of assigning it to a variable. Like
<?php
return array(
'var1' => 'something',
'var2' => 'something else'
);
Then you would be able to use it like this.
Config::load("/path/to/config/", "Config.php");
echo Config::$config["var1"];
While this will make the code behave the way you are trying to do it this is probably a bad idea. You should be using Dependency injection within your other classes instead of invoking the static property with your other classes. This will afford you a seam when doing testing and also allow your methods and classes to document in the constructor and method signatures exactly what is needed to perform a given task. See this video for more information on what DI is, and this google clean code talk to help understand why using statics like this is a bad idea.
Take a look at this: http://php.net/manual/en/function.parse-ini-file.php
But in simple terms you could so this:
config.inc.php
$config['var1'] = 'Hello';
$config['var2'] = 'World';
Then in your php:
include_once('config.inc.php');
or you could use this for an INI style include file: http://php.net/manual/en/function.parse-ini-file.php
config.inc.php
[first_section]
one = 1
five = 5
animal = BIRD
[second_section]
path = "/usr/local/bin"
URL = "http://www.example.com/~username"
Then in your php:
$ini_array = parse_ini_file("sample.ini", true);
print_r($ini_array);

When I move code into a function, I get a Fatal error. How can I call code from function

There are two pieces to this code:
One that adds documents to an index to be searched, which works fine, and a crawl() function that is a web-crawler that gets the contents of a page, which also works fine.
But, I need to add a document from inside the crawl() function.
When I move the code that adds a document inside the crawl() function, I get a Fatal Error:
Fatal Error: call to member function addDocument() on a non-object.
I am wondering how I can access the member function addDocument() from inside the crawl function?
Right now, I have a working version where the crawl() function returns what it has crawled in the form of a variable and then the addDocument code, outside the crawl() function, also has access to the returned variable and adds the document to the index that way.
But, that only (logically) works when I am crawling one page or a page with no links to follow. As the function only returns when it is done and since it is recursive to follow a page's links, the only content it will return is the content of the last-page.
Where I need the content of each page to be added each as a new document in the index.
Here is the working code, described above, commented as much as I could: http://pastebin.com/5ngcucDp
and here is the non-working code where I try to move the addDocument() inside the crawl() function: http://pastebin.com/mUEwQJTG
If you have a solution that involves how to access the addDocument() function from inside the crawl() function, then please share.
Or if you have a solution that involves modifying the working code so that it returns the contents of each page it crawls instead of the last-page, please share.
If you have any solutions, please share as I am absolutely exhausted and have tried everything I know.
When moving code to a function, you are completely removing its ability to access variables in the same scope. In this case, you probably (not going to go looking through your off-site code) have something like $someObject = new myClass();, then are trying to access $someObject->addDocument() on it from within the function.
You need to pass $someObject as a parameter to the function, or you could use global $someObject inside the function, though it's not as good an idea.
You have specified that:
// The below line is where the error takes place.
$elasticaType->addDocument($document);
Is your error line. Now, PHP is trying to access a class linked to $elasticaType If you have a linked class then use:
$elasticaType = new ClassName();
If not then you should create a class:
class Name {
public function addDocument ($document){
//Add document code
return $somevar;
}
}
$elasticaType = new Name();
$elasticaType->addDocument($document);

parameters & scope in functions

i have a question in PHP related to the parameters of a function and their scope.
I am building an own little template system and currently i keep using:
try {
$ret = include("file.php");
if(!$ret) {
throw new Exception();
}
// Go on here...
}
catch(Exception $e) {
// error handling
}
about 3-4 times in the mainfile index.php. This code first includes the needed file (set by GET parameters in the URL), trys to include it and if it fails it handles all errors. Since this is used 3-4 times in index.php i want to make a function out of it so i can easily call $Template->LoadFile("filename.php"); and this function handles everything for me: Including, Executing the code and error handling.
Not that hard i thought, but when doing so i get a lot of error messages because the variables needed by the included file for its execution are only avaiable in the scope of index.php (where the code was executed before) and not in the scope of the LoadFile() function. What can i do now?
Revert everything back and again use this above code 3-4 times stupidly?
Add all needed variables in LoadFile() as parameters so by using $Template->LoadFile($file,$vars); $vars would be available for use in LoadFile() for the included File? By doing so the given parameters would be huge in some cases. For example if i add an own board, the $vars would contain every board data and thats quite much. Wouldn't that make the template system really slow?
Add the needed variables via parameters as reference? (same as my 2nd suggest, but with less engine slowdown).
use globals? NO!
What options are there else? Thank's a lot :)
You can use option2 but in variety of other ways, have a look at how codeigniter and kohana render their views.
you can do something like
$Template->LoadFile($file, $vars)
where $vars is an array like array('thisIsVariableName' => 'thisIsVariableValue')
or
$Template->file($file)
->vars('thisIsVariableName', thisIsVariableValue)
->multi_var(array('thisIsVariableName2' => 'thisIsVariableValue2'))
->render();
In case of the template size, then you can always split a template into subtemplates.

"Global" variable scope in PHP

I have a section of code like the following:
---- file.php ----
require_once("mylib.php");
function($a,$b)
{
$r = $_GLOBALS['someGlobal'];
echo $r;
}
---- mylib.php ----
$_GLOBALS['someGlobal'] = "Random String";
This is a bit trivialized, but is the exact problem I have an I haven't found some related stuff, but nothing that answers my question directly.
When I call function($a,$b) nothing is echo'd, that is - $r is "empty" as if nothing was ever assigned to $_GLOBALS['someGlobal'];
In addition, I have tried with the following:
global $someGlobal;
$someGlobal = "Random String";
Same thing, no effect.
Also, in file.php if I try with global, or with just $someGlobal it still does not work.
As far as I know, from the documentation on php.net using global $someGlobal in mylib.php (and having that inserted in the top level of file.php) that it would not actually do much since it's already at the "top-level" of the scope hierarchy as far as I can tell. However, I thought registering it as a global might allow it to be accessed from inside the function, but this is clearly not the case.
Can anybody explain why, and explain how to get around this?
Edit: I should not that in file.php if I use $_GLOBALS['someGlobal']; the value is recovered fine if it's not in a function.
Wrong variable name. It's $GLOBALS not $_GLOBALS
http://www.php.net/manual/en/reserved.variables.globals.php
From the docs, there is no _ in the $GLOBALS variable:
This works fine for me:
$GLOBALS['glob'] = "string";
function foob() {
echo $GLOBALS['glob'];
}
foob();
It's $GLOBALS, not $_GLOBALS!

Categories