0

I know this is something silly, but I can't figure it out. I found a few similar questions all in the context of an MVC framework. That's my case as well, as I am using CodeIgniter.

I have a file questions.php (that's included in a view):

require_once '../site_init.php';

var_dump($siteVars);
// shows null and a Notice: Undefined variable: siteVars
// but the ABSPATH constant is showing as defined!
var_dump(ABSPATH);
// shows string 'c:\wamp\www\sitename'

require '../site_init.php';
var_dump($siteVars);
// correctly dumps the content of siteVars array

and a file site_init.php that should be included everywhere as it holds my site-wide configuration values:

if ( !defined('ABSPATH') )
        define('ABSPATH', dirname(__FILE__) . '/');

/** Site-wide sitevars */
$siteVars = array();

// set to true in develop environment
$siteVars['debug'] == false;

I know that The require_once statement is identical to require except PHP will check if the file has already been included, and if so, not include (require) it again however, when I am using require_once, I get a notice saying Undefined variable: siteVars, while using require, all works as expected. However, as you can see in the code above, the constant shows as defined, although they are both defined in the same file. PHP manual: Like superglobals, the scope of a constant is global. You can access constants anywhere in your script without regard to scope.

print_r(get_included_files()); shows site_init.php was included before the require_once, so I shouldn't have to require(_once) it again.

It must have something to do with variable scope. If I use global $siteVars, it works, without the need to require the file again, but can someone explain exactly why this happens? I am new to CodeIgniter. I can see there is only one entry point (the main index.php file) and that's the base file ($_SERVER['PHP_SELF']).

Ideally, I would also like to know how I can fix this without using global or require.

UPDATE: File structure seems to be the following (this is a project I am only working on, I am not the original developer):

  • controller welcome.php loads (include_once) a file X outside the CodeIgniter app folder structure (the CI app is the admin part of a larger site).

  • file X include_once site_init.php file

  • controller welcome.php loads the view $this->load->view('template', $data);

  • this is pretty much it. Hope this holds the key to a solution.

Community
  • 1
  • 1
bg17aw
  • 2,818
  • 1
  • 21
  • 27
  • http://stackoverflow.com/a/2418514/3599549. Has the page already been included earlier? – Krii Feb 12 '16 at 17:19
  • weird, I tested over here with 2 files, using require and require_once, both times succeeded. I was able to print the variable's content. – William Lee Feb 12 '16 at 17:26
  • What's your php version? I feel like codeigniter has nothing to do with this. Seems like a namespace problem, but it's weird saying so.... – William Lee Feb 12 '16 at 17:28
  • The question I linked to in my question explains it has to do with scope, and the fact that `global` solves this issue proves it's a scope problem. How did you test, do you have a codeigniter instal? I should give you my folder structure as well so you can replicate. – bg17aw Feb 12 '16 at 17:35
  • php version is 5.4.3 on wamp and 5.5 on production, both display same notice. – bg17aw Feb 12 '16 at 17:36
  • No, I don't have an instance of CI running here. But I was trying to require/require_once inside funcions and classes to try to simulate your problem. That's why I can't replicate the issue. – William Lee Feb 12 '16 at 17:45
  • Thanks, you can imagine I used require, require_once many times, and never had this issue, but MVC complicates the folder structure a bit. `get_included_files` reports 52 files in my particular case, most of them part of Codeigniter system (core files, system libraries and so on) – bg17aw Feb 12 '16 at 18:44
  • The first `require_once` is at global scope and not nested inside something like a class or a function? The `define` will be global but the variable won't be. debugging: add `$GLOBALS['siteVars_copy'] = __FILE__.__LINE__;` to the `sitevar` script. Then `var_dump($GLOBALS['siteVars_copy'], ABSPATH);` in your test script before the first require_once. – Ryan Vincent Feb 12 '16 at 19:53
  • @RyanVincent, var_dump result is `string 'C:\wamp\www\sitename\site_init.php14'`, as expected. Please see the question update, hope it answers your fist q. – bg17aw Feb 12 '16 at 20:49
  • 1
    imo, It is farly clear that you your `site_init.php` is being executed in the wrong place. It needs to be executed at the top level script (index.php?) not from anywhere within CI. Currently the `$siteVars` variable is `going out of scope` and being deleted shortly after creation ;-/ How to get around it. 1) Move the script to the top level; 2) Declare `SiteVars` as a `singleton` class. 3) assign it as property of the CI framework? i.e. `$this->siteVars = array();` etc. – Ryan Vincent Feb 12 '16 at 23:17
  • @RyanVincent, from what I can see, the variables are not available in the model either. Would it be bad practice to require_once this file in index.php? – bg17aw Feb 13 '16 at 20:43

2 Answers2

1

In CodeIgniter the only variables accessible in a view are passed to it from the controller. There should never be a reason to include anything in this way in COdeIgniter

Controller:

$d['title'] = 'title';    
$this->load->view('main',$d);

View:

<?php print $title;?>

see Config Class http://www.codeigniter.com/user_guide/libraries/config.html for custom config values which could then be accessed in the controller and passed on to the view

bg17aw
  • 2,818
  • 1
  • 21
  • 27
  • Thanks Matt, I think your answer is the key to a solution. I'll update if I manage to do it. – bg17aw Feb 12 '16 at 20:23
  • Hi Matt, I updated the question with more info, can you take a look, maybe it helps you be more certain towards what the problem is? – bg17aw Feb 12 '16 at 20:48
  • @bg17aw I So you do have access to the variables in the controller welcome.php but not in the view? – Matt in Washington Feb 12 '16 at 20:56
  • Yes, now that you asked. They are available in the controller. I don't have much experience with CI. – bg17aw Feb 12 '16 at 21:09
  • @bg17aw When loading a view the second argument is an array that will pass values or variables onto the view: in controller $d['siteVars'] = $siteVars; $this->load->view('viewname',$d); now in view $siteVars will be available – Matt in Washington Feb 12 '16 at 21:13
0

This is a logical problem, the scope just helps you see it. Here's the key to it:

print_r(get_included_files()); shows site_init.php was included before the require_once, so I shouldn't have to require(_once) it again.

This says that you've already included that file before, so require_once() doesn't do anything when you try it again. It's not that require_once() "doesn't load your variable", it just does what it should - avoid including a file that you've already loaded.
Obviously, require() doesn't care for that condition and it re-includes the script and hence imports the said variable in your current scope.

Anyway, including scripts again and again is a horrible method for getting data into your current scope. You should learn how to pass data around using function parameters.

Narf
  • 14,600
  • 3
  • 37
  • 66
  • you're only reformulating my own statements, I already know I am fully aware the file is included, and require_once doesn't do anything. However, I don't think including a site-wide init file is a bad idea, for once, the init file holds the `debug` switch, the root path and things like that. Like a wp-config.php file in WordPress. – bg17aw Feb 12 '16 at 19:22
  • Weren't you asking *why* it doesn't do anything? That's what I explained. – Narf Feb 12 '16 at 19:24
  • I might be missing something, I can't see how you answered the question. If you read the answers for the similar questioned I linked to, there is a good point in the right direction, as it is all to do with the MVC framework structure. – bg17aw Feb 12 '16 at 19:28
  • Well, I don't quite see exactly what you don't understand, so I can't clarify further. But one thing's for sure - it has nothing to do with MVC, nor with CodeIgniter. – Narf Feb 12 '16 at 19:31
  • I don't understand why you assume there is something 'horrible' going on, you also assume I do not know how to pass data around using parameters and your answer is not constructive in any way. You also say 'it's for sure not the MVC framework', an experienced coder/stackoverflow user would probably use something in the lines of 'I highly doubt'. Never say never. I updated the question to show better that the constant defined in the same file is ok, it is just the variable that is showing as undefined. Please stop assuming things. – bg17aw Feb 12 '16 at 19:35
  • So ... you can't understand why `require_once()` doesn't re-load a script, but you're questioning *my* experience and knowledge? Good luck, I'm out. – Narf Feb 12 '16 at 19:52
  • hmm... your comment/attitude is wrong on so many levels. I'll try to point out just a few: saying "this is a logical problem" is not really an answer, this can be said about most programming issues. If someone points out your not answering a question != they are questioning your experience/knowledge. You don't seem to understand (although you quoted me) that I mentioned myself the script is loaded so there is no way require_once would load it again. You don't seem to make sense, maybe you're having a bad night? The question is about scope, not about require_once, why and how to fix. – bg17aw Feb 12 '16 at 20:06