• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Confused about variables

#1
Hi there,

I'm very new to CI but have a background in programming.

I am trying to get my head round variables.

I've created my own controller (MY_Controller) which extends the CI_Controller, and has its own PROTECTED $data = array(), as suggested by many

I set some variables inside that array in the constructor of the MY_Controller class.

$this->data['counter']=1;

Then I've created another Controller which extends MY_Controller and I have a bunch of functions which basically call views which then call back into functions which change the value of that counter.

Problem is, the value doesn't change. For example, this function is supposed to increment the counter value and then call a view to show the counter

public function change_counter()
{
$a = $this->data['counter'];
$a = $a +1;
$this->data['counter'] = $a;
$this->load->view("show_counter",$this->data)
}

But it doesn't increment.

It seems that I can't actually change the value of the variables set in MY_Controller.

How does one change variables? Is the only way to do this sort of thing through Sessions? In which case what is the point of having the global data array in MY_Controller??


Yours,

Confused of Scotland.
Reply

#2
Static variables will always retain there value when set.

Google search php static variables
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#3
First, you would probably be better off setting a specific property for the data you need to store, rather than a generic $data array (but you should probably use more specific names, because there are potentially a lot of things attached to $this in the controller). In general, it should be quite rare to store data as a property of your controller, especially as a property of your base controller (MY_Controller).

Second, did you define a constructor in your extending controller (and, if so, did you remember to call the parent's constructor in the constructor)? If you did not define a constructor, you should be fine, but if you did define one and did not call the parent's constructor, then your parent's constructor isn't being called to initialize the data. The same goes for MY_Controller, did you remember to call parent::__construct() in MY_Controller's constructor?

Views shouldn't be calling controller methods. Whatever data the view needs should be supplied to it when you call $this->load->view() (as you've done when passing $this->data to it). A reference to a method from a view using $this might be resolved, but the context might not be what you expect, which may be the source of your issues (especially since you're relying so heavily on the context by changing properties in the controller).

Finally, when you call $this->load->view(), then exit the method called by the URL, once the loader finishes processing your view(s), that's the end of your response to the current request, and the data stored in your controller goes away. If you want data to be stored between requests, you need to use a session or store it some other way (e.g. a file, database, or cache).
Reply

#4
Hi there, thank you both very much for your replies.

I'd be very grateful if you would have a look at my responses.

I am still very new to web programming, having come from a Windows PC C# programming background a long time ago, so forgive me if I haven't quite got the point of all this yet.

(07-28-2016, 10:24 AM)mwhitney Wrote: First, you would probably be better off setting a specific property for the data you need to store, rather than a generic $data array (but you should probably use more specific names, because there are potentially a lot of things attached to $this in the controller). In general, it should be quite rare to store data as a property of your controller, especially as a property of your base controller (MY_Controller).

I guess I am just going with what I have seen from some of the tutorials online. I understand that variables/data should not be stored in controllers, as controllers retrieve data from the model and pass it to views, but I guess data in this context is being used to set up parameters that are being displayed on the view.

It seems to me that a variable defined in the constructor of a class is behaving more like a constant, in that you can set it in a controller's constructor, then use it in any of the methods in that controller, and even pass it to a view, but that it gets destroyed once the view goes out of scope so to speak.

Does that mean that every time a controller is called, a new instantiation of the class is created, used, and then destroyed once the page is rendered?

If that is so, then is the only way to return parameters set on a page by a user is either as POST data or as extensions to the URL?
i.e.
Code:
http://example.com/[controller-class]/[controller-method]/[arguments]

(07-28-2016, 10:24 AM)mwhitney Wrote: Second, did you define a constructor in your extending controller (and, if so, did you remember to call the parent's constructor in the constructor)? If you did not define a constructor, you should be fine, but if you did define one and did not call the parent's constructor, then your parent's constructor isn't being called to initialize the data. The same goes for MY_Controller, did you remember to call parent::__construct() in MY_Controller's constructor?

Yes, the constructor was defined - snippet shown below:

Code:
class MY_Controller extends CI_Controller
{
public $data = array();

function __construct()
{
parent::__construct();

//Set a value in the $data array to make sure that $data is initialised
$this->data['user']='USER variable in MY_CONTROLLER';
$this->data['counter'] = 4;

(07-28-2016, 10:24 AM)mwhitney Wrote: Views shouldn't be calling controller methods. Whatever data the view needs should be supplied to it when you call $this->load->view() (as you've done when passing $this->data to it). A reference to a method from a view using $this might be resolved, but the context might not be what you expect, which may be the source of your issues (especially since you're relying so heavily on the context by changing properties in the controller).

I am confused by this. If views can't call controller methods, then how do you control the flow of your site? I was of the understanding that was how one got back into a controller from a view?

If I can't do it using the method shown below (which as far as I can see is a call from a view into a method inside a controller) then how does one control the flow of one's site?

For example, to go to another page in the site from a button, I would use something like this:

Code:
<a href="<?php echo site_url('Start_here_controller/show_B_page')?>" class="button large">TEST_B VIEW</a>

and the code for show_B_page would be something like:

Code:
public function show_B_page()
{
echo ('$this->data[user] is ' . $this->data['user'] . '<br>');

$a = $this->data['counter'];
echo ('$a is ' . $a . '<br>');
$a = $a + 1;
echo ('$a is ' . $a . '<br>');
$this->data['counter'] = $a;
echo ('$a is ' . $a . '<br>');
echo ('$this->data[counter] is ' . $this->data['counter'] . '<br>');

$this->render('test_b');
}

(note the code above is test code for me to try and figure out how this stuff is working...)

(07-28-2016, 10:24 AM)mwhitney Wrote: Finally, when you call $this->load->view(), then exit the method called by the URL, once the loader finishes processing your view(s), that's the end of your response to the current request, and the data stored in your controller goes away. If you want data to be stored between requests, you need to use a session or store it some other way (e.g. a file, database, or cache).

I think that connects with my first response - if I want to pass parameters back from a view to a controller method, I have to pass it back as parameters on the method call - and this I guess results in a new instantiation of the controller.

So in order to store stuff, I either use sessions, or create a table in the database for variables. I can use parameters at the end of a method call to pass variables into a method as another way of controlling flow I guess...

It would that what I have been calling $data (defined as an array) can only be used as constants since that data can't be permanently changed as the class gets destroyed when the page has been rendered by the loader.

Am I on the right track?

I do apologise if these questions are really dumb.

Thanks for your help.

JB
Reply

#5
The questions aren't dumb, they just show an underlying assumption that is hard to let go of when moving from desktop programming to web programming (something I did myself a little over 10 years ago). Further, there are some differences between languages and environments that can make some web programming experiences more like desktop programming (ASP.Net and C# can blur the lines enough to make it easy to transition, but difficult to get a good picture of what's really happening). I do think you're on the right track, though. I apologize for the length of this in advance, and please feel free to ask if I missed something by not replying to your message point-by-point, because I felt it was easier to explain things in a different order.

In the normal case for PHP, a user follows a link, types in a URL, submits a form, or in some other way generates a Request, which, in the case of CodeIgniter (and many other PHP frameworks) is sent to a single script, index.php. That script usually handles the Request by instantiating a Controller and calling a method on that Controller instance. The Controller might load any number of Libraries and Models to deal with the Request, but, in the end, it usually loads one or more Views. When the Controller method called by the script ends, execution returns to the CodeIgniter script, which usually processes the View(s) and generates a Response, which is usually the page sent back to the user. At this point, the script is done, and execution ends. See The user guide's Application Flow Chart.

Your Controller instance terminates with the script once the Response is sent to the user, and anything stored in the Controller's properties is lost along with it.

So, if you want data to be maintained between Requests, you have to save it somewhere. Sessions allow you to setup a temporary storage which attempts to stick with the user between Requests (in PHP, a Cookie is almost always used to associate a Session with a user, but CodeIgniter does not store the actual Session data in the session Cookie, it stores it on the server according to the application's configuration). Sessions can be problematic for certain situations, and are never appropriate for data which requires long-term availability or needs to be available to multiple users. For those instances, you have the options of using a Database or writing to a file (caching is also an option, but is usually used more to speed up a site than for data storage; I should also add that CodeIgniter has a Caching Library which supplies wrappers for the most popular PHP Caches, but it also supports Output/Web Page Caching, Database Caching, and Query Builder Caching, all of which do very different things and are a source of endless confusion).

So, setting up a link in a View is fine, and it will direct a user back to your Controller. However, when the user clicks on a link on a web page, it is generating a completely new Request which is handled by a completely new instance of your Controller. It doesn't matter whether the page which contains the link was generated by the same Controller. It doesn't even matter if the user is submitting a form which posts the form data back to the same URL.

Now, if you just need to pass data to a method in the Controller, and it isn't important that the data is hidden from the user (and the data doesn't need to be shared between users), you can store it in the page. If the user calls the Controller method by clicking a link, then you would most likely store it directly in the URL which that link calls. If you're passing data to the Controller from a form, you might add hidden fields (<input type='hidden' name='something' value='your data here' />) to your form or put the data into the appropriate types of controls, then Post the form using a Submit button, at which point the Controller would access the data via $this->input->post(). Remember that the user can still choose to use a debugger or "View Source" in their browser to see whatever data you've put into hidden fields, and a debugger or other tools may even allow them to change the data. There are potentially a few other ways to pass data from a page back to a Controller, but these are the most common.

Something else I meant to mention earlier is that the Controller instance in CodeIgniter is a Singleton, and the Loader, along with most of the classes loaded by the Loader, gets attached to the Controller as properties. This is why you can access the Loader via $this->load->model()/library()/view()/etc., and why your loaded model becomes available via $this->model_name, or a library via $this->library_name(). This is also why I warn against using a lot of properties in the Controller, as you eventually run the risk of name collisions between properties and the loaded classes. Additionally, Models will search the Controller instance for any properties or methods which can't be found on the Model itself (allowing the model to access any currently-loaded libraries/models just as you would in the Controller). Finally, any public methods in the Controller which do not start with an underscore (_) can be routed, so they will usually be accessible via a URL (and, in PHP, any method or property which does not have its visibility declared is public).
Reply

#6
This is restating one of mwhitney's points using different language.

There is a concept that is key to understanding web programming - the web is a stateless protocol. As such, it treats each request as an independent transaction that is unrelated to any previous request. Communication consists of independent pairs of request and response. The server does not retain information or status about each communications partner for the duration of multiple requests.

In other words, the server receives a request, processes it, replies and promptly forgets all about it. It is all too easy to forget this fact when programming for the web.

There is a PHP extension that provides a way to preserve certain data across subsequent accesses -  sessions. CodeIgniter provides a library that simplifies the use of PHP's sessions. Session library documentation here.
Reply

#7
Gentleman,

Those responses are absolutely brilliant and have provided answers to the questions that I have been asking for days. Thank you very much indeed for taking the time to post.

I see now that I hadn't quite grasped the concept of statelessness that comes with dealing with web pages.

One final question to just clear things up well and truly. Does all this mean that what are often called variables when referring to controllers are actually just statics, and are more akin to constants given that the controller and everything associated with it are destroyed once the view is rendered and served out to the user?

Thanks again for two very very useful posts.

JB
Reply

#8
(07-29-2016, 08:44 AM)MightBeABitLate Wrote: Does all this mean that what are often called variables when referring to controllers are actually just statics, and are more akin to constants given that the controller and everything associated with it are destroyed once the view is rendered and served out to the user?

While it is true that everything associated with the controller are destroyed once the view is rendered and served out variables are well... variable. They exist while the script is executing and can be assigned new values. Constants cannot be assigned new values once defined.

In PHP a static variable relates to variable scoping. Static variables exist only in a local function scope, but it does not lose its value when program execution leaves this scope. The must be explicitly declared as static ie. static $count = 0;

I suppose that class properties that are variables might be considered static in that they maintain an assigned value for the lifetime of the class - except they never go out of scope in the context of the class.
Reply

#9
Constants and variables are different things. Variables do not need to be declared before use and contain data that may or may not change during processing. Constants have to be defined and are used for static values like config variables. (Although PHP magic constants may vary, just by their nature, like line number).

PHP Code:
// Defining a constant
define("PROGRAM""PHP");

// Setting a variable
$txt "Hello World!"

Usually people refer to these in a loose kind of way as variables are just named values that are able to vary, although usually the intention is clear. For instance a variable can refer to an arguement passed to a class method. eg: method foo and variable bar as an argument.

PHP Code:
function foo($bar)
{
 
   return $bar;


Hope that helps. The PHP docs are excellent in this respect and are well worth a good read. Although you can gloss over alot of it when you first start out, it is worth re-reading regularly. Like an encyclopedia, there is an awful lot to cover.
http://php.net/manual/en/langref.php

Paul.
Reply

#10
(07-29-2016, 08:44 AM)MightBeABitLate Wrote: Gentleman,

Those responses are absolutely brilliant and have provided answers to the questions that I have been asking for days. Thank you very much indeed for taking the time to post.

I see now that I hadn't quite grasped the concept of statelessness that comes with dealing with web pages.

One final question to just clear things up well and truly. Does all this mean that what are often called variables when referring to controllers are actually just statics, and are more akin to constants given that the controller and everything associated with it are destroyed once the view is rendered and served out to the user?

Thanks again for two very very useful posts.

JB

The previous answers probably do a good enough job of describing the differences between static variables, constants, and just plain variables. CI's Controller can add to the confusion because it incorporates the use of static variables to load many of its classes as Singletons (including the Controller itself), and most of your code will run within that Singleton.

So, a property on a Controller is a property of a class which happens to be executed as a static variable, but the property itself is not static (unless it was defined as static). Since most of your code is executed within the scope of the Controller, with access to most of the Controller's properties and methods, it's possible that your property can be accessed by most of the other code executed after it is defined. However, if you define properties in your Controller specifically for the purpose of accessing them from other classes, you will find that it limits your ability to reuse your code. It also can make it very difficult to read and understand the code later.
Reply


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2019 MyBB Group.