I have an index.php file that has 3 includes
<?php
require_once('mod.php');
$mod = new Mod();
require_once('start.php');
require_once('tools.php');
....some code....
?>
I need to be able to reference the $mod object inside the start.php and tools.php.
How do I pass that object to be referenced by those 2 other require files?
Basically the mod.php is a class that has an array list generated in its __construct(). I want to use that array list data inside the startup.php and tools.php file but not sure how to pass in the existing one without calling "new" inside both of those files separately which doesn't do what I need since it resets everything.
Thanks!
It looks like you're using require() calls not for dynamic functionality loading (get a class definition in), but as something like a function call. Don't. Avoid global variables like a plague.
Side note: Instead of worrying about doing the require() calls in the right order to get your classes defined, I'd encourage you to look at Autoload functionality in PHP 5. It allows you to define which classes are defined in which file, and load those files on-demand when the classes are requested.
First of all use some autoloader. Dozens of require on the top of the file are annoying and needless.
You don't have to pass any references to other files. require works like "copy-paste-execute" so $mod will be available in that file.
#index.php
$mod = new Mod();
include 'file.php';
#file.php
$mod->doSth(); // works file!
Your problem is probably variable scope. If you need to use $mod inside another object (the fact that its source (class) is in another file doesn't matter) pass reference to $mod as a constructor argument, pass it using a special setter ($obj->setMod($mod); $obj->doSth();) or use more complex but better solution like Dependency Injection Container (sample implementation).
Doing require (or require_once, include, or include_once), simply includes and evaluates the code. The variable scope is inherited from the point at which the code is imported.
As an example, using your code:
<?php // index.php
require_once('mod.php');
$mod = new Mod();
require_once('start.php');
And the include:
<?php // start.php
$mod->arrayList(); // $mod is the object created in index.php
The mod should be available in those other files...if you need it in a function or class, use the global keyword, like:
function test() {
global $mod;
print $mod->list;
}
Related
I have the following code:
<?php
session_start();
require_once('ClassFile.php');
use ClassFile\Component;
include 'somefile.php';
?>
Within this template I can access properties of the Component (e.g. $comp = new Component();). However, Component is not visible from within somefile.php. I get an error to the effect that it does not exist. The (poor) workaround is to copy the same code in somefile.php. Can anyone say what's going on? Do I need to somehow globalize the items in the require_once and use statements? Thanks.
If you mean that you cannot do new Component inside somefile.php, that's because the class is called ClassFile\Component, not Component. The use alias does not extend to included files. If you want to alias ClassFile\Component to Component in somefile.php too, you have to write the appropriate use statement in that file too.
Namespacing is always per-file.
I have a class called Page, which loads a PHP file for the current page, containing all the HTML (template file). In my template file, I want to use instances of other objects, that is initialized outside the Page class (ex. User, PDO or other classes). My problem is, how I do this the smartest way.
In my page class i have a method called get_page() which loads my template file (containing all the code for my GUI.
public function get_page() {
// Load theme template
...
$template_file = ABSPATH_THEME . 'tpl.' . $result['template_file'] . '.php';
if(file_exists($template_file)) {
$page = require_once($template_file);
return $page;
}
}
As you see the template file are loaded inside my Page class, and therefore will it not access instances of classes initialized outside my Page class.
I can come up with different solutions:
1) I pass all instances of the different classes to my class Page, when constructing my page. I think this is the right way, but can be very complex if I need 5, 10 or 20 different objects in my design.
2) Find a way to include the template file outside the Page class, but triggered from the get_page() function - have no clue how to do this, and if it is a good solution?
Can you please tell me what is best, and if there are some better ways to do it?
You can just include classes on the top of your php
eg. /CLASSPATH/ClassName.php
And then you can create an entity for that class once and use it everywhere
eg. $entity = new ClassName();
I think your best bet will be to pass them in as arguments, depending on what you need you may want to make them properties.
Edit: This is assuming that by "using instances of other objects" you mean that you need to use objects that have already been instantiated elsewhere.
If by "istances of other classes" you mean other generical objects (you mention PDO and user which are goos examples of this) I would store these in the $_SESSION array (or in $_GLOBAL array, $_SESSION being the best option in most cases).
Then you can access them just by using $_SESSION['PDO']->... and the like
One of the most popular method to handle php application rooting is to implement MVC design patern, or use an MVC Framework. Google 'MVC php' for details, good luck.
Take a look at the functions get_defined_vars and extract. Using these you can export variables from one scope to another.
A silly example could be: A function A transfer locally defined variable to a function B.
function A()
{
$var1 = "1";
$var2 = "2";
// etc
$data = get_defined_vars();
B($data);
}
function B($data)
{
extract($data);
// somescript.php can use $var1, $var2, etc if B is call from A.
require("somescript.php");
}
A();
The best practice is to use a ServiceLocator or an InversionOfControll-Container to retrieve class instances without violation of DI-Principle. For your template file you can create view helper objects to have direct access to other objects.
I have 2 files, class.inc.php and index.php.
class.inc.php contains Myclass and few functions, index.php file spits out functions from class.inc.php.
Now I need to create a function which will include/require a file and that function should actually require that file in index.php not in class.inc.php.
Yes I know I can place my file in a function and call it that way but we have to keep it in files because of some future MVC overrides. I do not want to include a file in index.php directly either if all possible. So is there a way to do this?
In my index.php I should be able to do this:
Myclass::include(PARAMS);
and that should include a file name params.php located somewhere else.
I tried this in class.inc.php
abstract class Myclass {
static function load($filename){
require_once $filename;
}
}
and this in
index.php
Myclass::include(PARAMS);
but none of my variables from params.php are visible in index.php because they seem to be in class.inc.php.
include, require and friends basically act as though you had copied-and-pasted the contents of the file to that location. So if you run them in a function, any "bare" variables, which would be global if you ran the file on its own, are instead local to that function.
Generally speaking, the answer in modern PHP code is simply not to use any global variables - a file should contain only functions, or better still, only namespaces and classes, with all the variables wrapped up in those.
If you really need to have global variables, however, you can use the global keyword either in your include function or at the top of the included file.
So for instance if your included file defines a variable $config which needs to be accessed elsewhere, at the top of the file you can write global $config; to push it out of any scope you're in when you include/require it.
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).
i want to have a class that includes all files for me.
eg.
Loader::loadZend // loads all zend libraries
Loader::loadSymfony // loads all symfony components
if i include a file in a method, does this become globally available?
it seems that it doesnt work.
maybe i have done something wrong, or is there a workaround for this?
thanks
From http://uk.php.net/manual/en/function.include.php (emphasis mine)
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.
Having a loader that loads all classes of Zend, Symfony or whatever at once is a bad idea. Both have their own autoloader, so all you need to do is make the libraries available on the include path and then spl_autoload_register the framework's own autoloader.
If no global scope variables are defined, you should be fine. Otherwise, the globals will be lost.
For example,
a.php:
<?php
$a = "global a";
class c {
public $b = "member b";
}
?>
b.php
<?php
function inc() {
include 'a.php';
}
inc();
echo $a;
$class = new c;
echo $class->b;
?>
If you run b.php, you will find out $a is gone and class c or any function will still be available.
If you just include a class inside another class it is only available in the class you inserted the include.
So the solution is to create an autoloader that automaticly includes the classes needed on demmand. Here you have the info you need:
http://php.net/manual/es/language.oop5.autoload.php
It is basic programming for PHP5 OOP.
EDIT
Seeing your inquiry about a file. Neither. The file (to be processed via php functions) will only be available inside the function where it is called/used for, not globally in the whole application / website.