I'm trying to introduce CI into a legacy application but want to use some of the globals that already exist externally from CI. I have been loading them into /CI/config/config.php and acquiring them using this in the view:
$this->config->item('myvar');
That works fine. However, if I include my sidebar in the model called sidebar.php, which wants to access the globals stored in globals.php they come up as undefined. Note that sidebar.php uses a include statement to access globals from globals.php. Also, the globals are defined like this in globals.php:
$myvar = "bla";
globals.php and sidebar.php are outside of CI. These two files don't need to execute functions.
Does anyone know of a trick to allow CI and files it includes to access globals outside of it? I don't want to change the legacy code too much.
Codeigniter provides a useful helper function to solve these kinds of situations. The get_instance() function will return the singleton object so that you can access it's many wonderful features. Below is an example of how you might do this.
$ci =& get_instance();
$ci->config->item('varname');
Here is the documentation. You'll find the reference under the title Utilizing CodeIgniter Resources within Your Library
It turns out I found an include_once statement for the globals.php file in a place where the legacy code couldn't access it. The legacy code already had an include_once statement but it was ignored b/c it was already included elsewhere.
I assume that it's acting similar to this in CI if I open testfile.php:
testfile.php:
include_once("globals.php");
function testf(){
include("sidebar.php");
}
testf();
sidebar.php
include_once("globals.php");
echo $myvar; //fails
Related
I have PHP files a bit like this
public_html/environment.php
public_html/task.php
phpbin/actions.php
phpbin/library.php
environment.php is included by public_html/* before any other php files are included, phpbin/* assumes everything in environment.php is already available.
It defines these two globals
$g_foo = "...";
$g_bar = "...";
task.php includes this logic
function do_stuff ()
{
require_once determine_required_file ();
...
}
In this case, determine_required_file() returns "/path/to/phpbin/actions.php"
actions.php in turn contains
require_once "/path/to/phpbin/library.php"
Finally, library.php contains
$x = $g_foo;
$y = $g_bar;
I get this error:
Undefined variable: $g_bar;
Now, $g_foo and $g_bar are strictly read-only except in environment.php, I have exhaustively grepped and verified that there are no other places which create or modify variables with these names.
I am aware that PHP globals are weird, and doing things like including files from within functions can mess up your scope. I know that I should probably use define() or some other method, yeah yeah.
My question is this (yes, I'm asking you to speculate in the absence of full code, sorry):
Why might $g_bar generate an error but not $g_foo?
I assume the in-function-inclusion is probably responsible, but assuming these globals really are read-only, what should I be looking for as the culprit for why one ends up in global scope in library.php but not the other?
You need to use include_once instead of required_once for your fields that needed your global variables, or define a global $g_bar, $g_foo.
http://php.net/manual/en/language.variables.scope.php
Say I want a constant, a function or a class to be available in all my models, views and controllers code (within a particular web site (application)). Where can I put them? I don't mind importing them explicitly in every file I need them in but I don't know how (simple require_once does not seem to work).
You can put them in the vendor folder (in application/vendor or modules/MOD/vendor). Then you can load it like this:
require Kohana::find_file('vendor', 'folder/file','ext');
You can read up more on this in the user guide
Now, it should be stated you should in general not use functions or globals.
I declare Constants in Bootstrap.php and create my own Helpers for general functions under application/classes/Helpers.
If you need to integrate a third party library into Kohana or want to make code available to other Kohana users consider creating a module instead.
You can define all your constants in new php file and place it in the application/classes directory. In your Template controller or in the main controller like Welcome or Website, just place the code in the __constructor()
require_once Kohana::find_file( 'classes', 'filename' );
I suggest you to put your constant variables in the bootstrap.php file because this is loaded by the framework before every request.
You can simply put your classes in the root of the classes directory, the framework will find.
This worked well for me...
In application/config/constants.php:
define('SOME_COOL_CONSTANT', 'foo');
return array();
In index.php:
Kohana::$config->load('constants');
SOME_COOL_CONSTANT should then be available globally.
I am having problems with some legacy code that I am trying to add to a Yii project.
It has to do with global variables, which I am well aware should instead be passed as parameters, but since this old code and is used in other projects rewriting it is not really and option.
$testVar = '123';
function testOutput() {
global $testVar;
var_dump($testVar);
}
testOutput();
Now if I include this file in a plain php file it works and outputs
string '123' (length=3)
But if I include this file in a Yii controller or even in a template it output this
null
I have tried to search for this issue but I just get a bunch of results about people using global variables incorrectly. I am sure it is not actually a Yii issue but most likely a php_ini setting that Yii is setting, but I can't find anything when searching the code or the Yii docs that would explain this.
This example can be tested by just creating a file with my first code block and then include it into a Yii template or controller. I even tested it with a clean example Yii project.
I hope I didn't hurt my chances of figuring this out by tagging this questiong with Yii since I have a feeling that it is not just a Yii specific issue.
Any insights would be greatly appreciated.
If you do like this, it will work, I just tested with Yii controller
global $testVar;
$testVar = '123';
function testOutput() {
global $testVar;
var_dump($testVar);
}
testOutput();
As DCoder mentioned, if youre declaring them inside a class, function/method then they are not global. You can try assigning them to the $_GLOBALS array though:
$GLOBALS['testVar'] = 123;
However depending on the legacy code and how youre integrating it you may need to change all references in that legacy code to use $GLOBALS['thevar'] instead of $thevar or do an extract($GLOBALS) at the top of some or all of the legacy files.
Googled: Global Variables in Yii
I've got a scope problem here. and no idea why its not working, ive got a setup as follows:
functions.php
global $id;
$id = $_GET['id'];
index.php
require_once('functions.php');
echo $id;
now inside functions.php i can echo out $id. however my echo $id; inside index.php is bringing up blank. absolutely nothing.
what am i doing wrong?
In PHP, the global keyword allows you to reference variables in the global scope from inside a local scope - eg to access a global variable inside a function. You don't need global in your example, because you are in the global scope anyway.
I suspect you are showing us a simplified version of what you have, where the issue is in code you haven't shown us.
Why you shouldn't use globals
Confusion like this is part of why using globals is a bad idea and should be avoided.
The alternative is to pass variables around explicitly, so for example if you call a function or instantiate a class from another file, you pass the variable in as a parameter to that function or constructor. Doing this, instead of using global variables, makes it easier to follow what function is accessing what variable because you can follow the trail easier.
You don't need globals between files, only for functions.
Functions.php
<?php
$foobar = "Hello";
?>
Index.php
<?php
include('Functions.php');
echo $foobar;
?>
You shouldn't use globals, but you have it backwards. You declare the variable global after you include its definition:
file1.php:
$name = 'Josh';
file2.php:
require_once('file1.php');
global $name;
echo $name;
#thomasrutter is correct (+1) Global variables areA Bad Thing. Always seek alternatives.
Perhaps you can use $_SESSION (which sort of amounts to the same thing, I know), or declare a class which has a static variable and use a getter() and setter() ? (the latter uis definitely cleaner, but $_SESSION might tie in better with your design, I can't say)
Btw, I hope that functions.php was just an example name, or that you have an extermely simple project.
Otherwise fucntions.php is going to get extermaly large and hard to oversee. If you are going OO then user one file per class, otherwse try to group your functions into separate files (file_management.php, databse.php, forms.php and the like).
If you are just starting out, I would advise you to use Netbeans and document your code with PhpDoc comments which will allow you to generate good documentation which you can view in your browser (including the structure of your coed, what gets declared where, used where, descruptions of function parameters and return values, etc)
Btw, I notice that you use include() I prefer require_once. The _once helps spee dperformnce a little and hte require makes sure that you are aware of missing files more quickly.
Oh, and learn to use Xdebug, which plays well with NetBeans.
A pattern I tend to use often in PHP is setting a few globals (such as $page, $user, $db, etc), and then including a file which uses those globals. I've never liked the idea of using globals for this, though, so I'm looking for a better way.
The obvious solution is to define a class or function in the subfile, and call it after the file is included. There are cases where that can't work though, such as this:
// Add entries to a URI table from each section of the site
global $router;
$router = new VirtualFileSystem();
$sections = array('store', 'forum', 'blog');
foreach($sections as $section)
include dirname(__FILE__) . $section . '/routing.php';
// Example contents of 'forum/routing.php'
// implicitly receive $router from caller
$router->add('fourm/topic/', 'topic.php');
$router->add('forum/topic/new/', 'new_topic.php');
// etc
If I tried to wrap each routing.php in a function and call them each with $router as an argument, the same function name would clash after being defined in multiple files.
I'm out of ideas. Is there a better way to pass variables to included files without polluting the global namespace?
include and its siblings are basically just copy-paste helpers, and the code inside them shares scope with the calling block - as if you'd copy & paste it just where the include statement is. The sane way of using them is to think of them the same way you'd use #include in C or using in C# or import in Java: import some code to be referenced later on. If you have code in the included file that needs parameters, then wrap it in a function, put the parameters in the function arguments, use include_once at the top of the including file, and call the function with the parameters you want, wherever you need to. No globals required. As a rule of thumb, in regular operation, putting any code that "does" something (executes statements in the global scope) in an included file is best avoided IMO.
No, there is not. You're not passing variables to included files anyway. The code that is included behaves as if it was written where the include statement is written. As such, you're not passing variables into the included file, the code in the file can simply use the variables that are in scope wherever the include statement is located.
In your case the contents of forum/routing.php are not really standalone code, they're code snippets that depend on a very specifically set up scope to function correctly. That's bad. You should write your includable files in a way that does not couple them to the including code. For example, you could make your Router a static class and call it statically in forum/routing.php:
require_once 'virtual_file_system.class.php';
VirtualFileSystem::add('forum/topic/', 'topic.php');
As long as there is a class VirtualFileSystem in your app, this will work, and won't pollute the namespace any more than it already is anyway.
just isolate includes in a function:
function add_entries_to_router($router, $sections) {
foreach($sections as $section)
include dirname(__FILE__) . $section . '/routing.php';
}
$router = new VirtualFileSystem();
add_entries_to_router($router, array('store', 'forum', 'blog'));
You can try an OOP way by making a Configuration class as a singleton and retrieving it when you need it.
You could define magic methods for __get and __set to add them to an private array var and make the constructor private.
I usually define as constant only the path to my src project in order to load class files quickly and properly (and use some SPL too).
But I agree with #tdammers about the fact that an include keep the environment variables like if you were on the caller file (the one who makes the include).