I've been looking at some code and am having a hard time working out variable declaration in php classes. Specifically it appears that the code i'm looking at doesn't declare the class variables before it uses them. Now this may be expected but I can't find any info that states that it is possible. So would you expect this:
class Example
{
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
to work? and does this create these variables on the class instance to be used hereafter?
This works the same as a normal variable declaration would work:
$foo = 'bar'; // Created a new variable
class Foo {
function __construct() {
$this->foo = 'bar'; // Created a new variable
}
}
PHP classes are not quite the same as in other languages, where member variables need to be specified as part of the class declaration. PHP class members can be created at any time.
Having said that, you should declare the variable like public $foo = null; in the class declaration, if it's supposed to be a permanent member of the class, to clearly express the intent.
So would you expect this: (code sample) to work?
Yes. It's pretty bad practice (at least it makes my C++ skin crawl), but it wouldn't surprise me in the slightest. See example 2 in the following page for an example of using another class without declaring it beforehand. http://www.php.net/manual/en/language.oop5.basic.php It will throw an error if E_STRICT is enabled.
And does this create these variables on the class instance to be used hereafter?
Yep. Ain't PHP Fun? Coming from a C++/C# background, PHP took a while to grow on me with its very loose typing, but it has its advantages.
That's completely functional, though opinions will differ. Since the creation of the class member variables are in the constructor, they will exist in every instance of the object unless deleted.
It's conventional to declare class member variables with informative comments:
class Example
{
private $data; // array of example data
private $var; // main state variable
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
Related
I am having trouble understanding how to work with objects.
The specific code:
class first{
class second{
public function widgets(){
$a_variable = $a_value;
}
#1
}
$second = new second;
#2
}
#3
$first = new first;
If I initialize $a_variable as $a_variable it is only available inside the function, correct?
If I initialize $a_varialbe as $this->a_variable it is only available inside class second, correct?
Can I initialize $a_variable as $first->second->a_variable? If so, How would I call it at #1, #2, and #3?
Can I initialize $a_varialbe as $this->second->a_variable? If so, How would I call it at #1, #2, and #3?
As you can see I am simply confused as to how OOP works.
First of all, I want to express how much I appreciate all of the help. I have already learned more than enough to consider this question a smashing success.
That said, even if it is poorly formulated, psuedo-code and invalid syntax, this code DOES run.
class class_1{
public function function_1(){
require('class_2.php');
public function function_2_callback(){
//%%%%%% How do I set a variable here and get the DATA...
}
$this->class_2 = new class_2("function_2_callback");
}
}
$class_1 = new class_1;
//&&&&&&&&&& Get the DATA here?
/* CONTENTS OF class_2.php */
class class_2($callback){
call_user_function($callback);
}
Even if we have to look at this as an exercise. Can someone tell me how I would first set (# %%%%%%%)and then call a variable (# &&&&&&&&) as shown?
First off: What you have there doesn't work, you cannot declare a class inside a class the way you are doing (notwithstanding conditionally declaring a class inside a function, which you should not do).
Scope in PHP (including OOP) is very simple:
variables have function scope
object properties are accessible if you have a reference to the object
the visibility of object properties can be restricted
The only real scope you have is function scope for variables:
$a = 'foo';
function bar() {
$a = 'bar';
}
The two $as are entirely unrelated, in different scopes. As simple as that.
class Foo {
public $a = 'foo';
public function bar() {
$this->a; // foo
$a = 'bar';
}
}
$foo = new Foo;
$foo->a; // foo
An object property has no scope, it has visibility. You can access it if you have the object in scope. Above, $foo is the object. It's in scope, its property a is public, therefore it can be accessed using $foo->a. Inside the class, the property is accessible via $this->a.
The $a = 'bar' is a local variable in the function and has nothing to do with $this->a. It is not accessible anywhere except inside the function. Refer to rule #1, function scope.
class Bar {
protected $b = 'bar';
public function baz() {
$this->b; // bar
}
}
$bar = new Bar;
$bar->b; // doesn't work
If the visibility is not public, the property (here b) is not accessible from outside the class itself. Inside the class you can access it using $this->b, but not from outside using $bar->b. It's not about scope, but visibility.
And that's pretty much the scope rules in PHP.
First of all your example is invalid code
PHP does not support nested classes, meaning a class within a class.
if you define a class, a variable initialized within a method is local to that method, while you can "initialize" an attribute with $this->newattribute, you should have declared it and its visibility before (before you write a method public / private / protected $varname = "initial value";).
Your questions 3 and 4 would make sense in another context, this is when an object is passed as member of another object, see example below.
If you build it like
<?php
class First {
public $second;
}
class Second {
public $a_variable;
}
$foo = new First();
$foo->second = new Second();
you can access it:
$foo->second->a_variable = "foo";
or within a method in second with
$this->a_variable;
or within a method in first with
$this->second->a_variable;
You should NOT be nesting classes like that. That shouldn't even run. I would suggest running the code first. There are some tools online for testing small snippets of PHP code, such as this.
For the code to run as you might expected it to, it should look like this:
class second{
public function widgets(){
$a_variable = $a_value;
}
}
class first{
public $second;
public function __construct() {
$this->second = new second;
}
}
$first = new first;
A variable that begins with $[a-z]+ is local to the function. A property beginning with $this->[a-z]+ (where [a-z] is 1 or more letters) is part of the object.
There's some documentation on php.net that goes over the specifics of objects in php here.
If I initialize $a_variable as $a_variable it is only available inside
the function, correct?
Yes, correct. It begins with $[a-z]. Not quite true if you use the global keyword, but that's discouraged.
If I initialize $a_varialbe as
$this->a_variable it is only available inside class second, correct?
Yes, but you should declare it first. You can do this with public $variable, protected $variable or private $variable. public means a property can be accesses from the outside, whereas private means only the class itself can access it. protected is private to the outside, but public to classes that extend from your class.
(public/private/public became available in PHP 5. In PHP 4 you would use var $variable, which defaults to public in PHP 5)
Can I initialize $a_variable as $first->second->a_variable?
You can arbitrarily initialize class variables without declaring them, but that's not something you should be doing.
If so, How would I call it at #1, #2, and #3?
You can't call code there (in your example). Code must be inside a function or in the global context (outside of the class definition).
A Brief Explanation of Classes
class foo{
// This can be accessed anywhere
public $i_am_public;
// This can be accessed within this class and any sub classes
protected $i_am_protected;
// Thi can only be accessed within this class
private $i_am_private;
// This function can be accessed anywhere
public function foo_function(){
// This variable is only available in this function
// it cannot be accessed anywhere else
$variable = 'Hello World';
// However, you can access any of the other variables listed above
// like so
$this->i_am_public = 'public';
$this->i_am_protected = 'protected';
$this->i_am_private = 'private';
// Write these variables
echo $this->i_am_public;
echo $this->i_am_protected;
echo $this->i_am_private;
}
}
$foo = new foo;
$foo->foo_function();
// You can change any publicly defined variables outside
// of the class instance like so
$foo->i_am_public = 'testing';
Specific Answers to Questions
Before I go any further, I would hugely urge you not to define a class within a class! Instead, use class extensions which I will explain later. In fact, I am surprised your code even works!
If I initialize $a_variable as $a_variable it is only available inside
the function, correct?
Yes, this will only be available inside the function. If you want to access it outside of the function then you need to define it outside the function using one of the scope definitions public, protected, private.
If I initialize $a_varialbe as $this->a_variable it is only available
inside class second, correct?
This depends on what scope you give it, but you shouldn't be defining a class within a class anyway.
Can I initialize $a_variable as $first->second->a_variable? If so, How
would I call it at #1, #2, and #3?
I cannot answer this as I have never nested a class within a class, once again I would urge you to change this structure.
Can I initialize $a_varialbe as $this->second->a_variable? If so, How
would I call it at #1, #2, and #3?
Please see above answer :-)
Nesting Classes
As mentioned, I have never seen this before, and I am surprised it even works. You should definitely change this structure.
One suggestions would be to use extensions like so:
class foo{
// This can be accessed anywhere
public $i_am_public;
// This can be accessed within this class and any sub classes
protected $i_am_protected;
// Thi can only be accessed within this class
private $i_am_private;
public function foo_function(){
echo 'Hello World';
}
}
class bar extends foo {
// This is a public function
public function baz(){
// These will work
$this->i_am_public = 'public';
$this->i_am_protected = 'protected';
// This will not work as it is only available to
// the parent class
$this->i_am_private = 'private';
}
}
// This will create a new instance of bar which is an
// extension of foo. All public variables and functions
// in both classes will work
$bar = new bar;
// This will work because it is public and it is inherited
// from the parent class
$bar->foo_function();
// This will work because it is public
$bar->baz();
This is somewhat a follow up to a previous question - but I've distilled the question down and have the "works" vs. "doesn't work" cases narrowed down much more precisely.
My Goal:
I have a class MyClass that has an instance variable myFunction. Upon creating a MyClass object (instantiating), the constructor assigns the instance variable myFunction with the result of a call to create_function (where the code and args come from a db call).
Once this object of type MyClass is created (and stored as an instance variable of another class elsewhere) I want to be able to call myFunction (the instance variable anonymous function) from "anywhere" that I have the MyClass object.
Experimental Cases -- below is my highly simplified test code to illustrate what works vs. what doesn't (i.e. when the expected functionality breaks)
class MyClass extends AnotherClass {
public $myFunction;
function __construct() {
$functionCode = 'echo "NyanNyanNyan";';
$this->myFunction();
/*Now the following code works as expected if put in here for testing*/
$anonFunc = $this->myFunction;
$anonFunc(); //This call works just fine (echos to page)!
/*And if i make this call, it works too! */
self::TestCallAnon();
}
public function TestCallAnon() {
$anonFunc2 = $this->myFunction;
$anonFunc2();
}
}
However, if I do the following (in another file, it errors saying undefined function () in... within the Apache error log.
//I'm using Yii framework, and this is getting the user
//objects instance variable 'myClass'.
$object = Yii::app()->user->myClass;
$object->TestCallAnon(); // **FAILS**
or
$func = $object->myFunction;
$func(); // ** ALSO FAILS **
In addition, several variations of calls to call_user_func and call_user_func_array don't work.
If anyone is able to offer any insight or help that would be great :).
Thanks in advance!
You can't pass references to functions around in PHP like you can in for instance JavaScript.
call_user_func has limited functionality. You can use it like so:
class MyClass {
function func() {}
static function func() {}
}
function myfunc() {}
$i = new MyClass();
call_user_func("myfunc", $args);
call_user_func(array($i, "func"), $args);
call_user_func(array(MyClass, "staticFunc"), $args);
I ended up solving this issue via a workaround that ended up being a better choice anyways.
In the end I ended up having a static class that had a method to randomly return one of the possible identifiers, and then another method which accepted that identifier to build the anonymous function upon each class.
Slightly less elegant than I would like but it ends up working well.
Thanks to everyone for your efforts.
I noticed two ways in PHP to do the same thing. Can you tell me which way is a better programming practice?
In the first example, I use a private variable on the class. On the second example, I use a static variable in a class method.
class Test {
private $_myvar;
public function getVar(){
if (!isset($this->_myvar)) {
$this->_myvar = "test\n";
}
return $this->_myvar;
}
}
$oTest = new Test();
echo $oTest->getVar(); // sets var first time and returns it
echo $oTest->getvar(); // pulls from cache
Or:
class Test {
public function getVar(){
static $myvar;
if (!isset($myvar)) {
$myvar = "test\n";
}
return $myvar;
}
}
$oTest = new Test();
echo $oTest->getVar(); // sets var first time and returns it
echo $oTest->getvar(); // pulls from cache
That is like saying which room is better the Kitchen or the Bathroom, they are both rooms, but they have different functions.
A static variable is the same in multiple objects.
An instance variable, declared via private above is particular to a given object.
Note that private is an access modifier, static is not, a variable can be both.
In the location you have your static variable, within the function, it is not a class/object variable at all, but a traditional function-level static variable, which will be single-instanced across all calls to the function, making it similar to a class-level static variable, but only accessible within the method it is defined within.
With the class property (be it public, private or protected), the variable is accessible to other parts of the class.
With the static variable, it is only visible to that method of the class.
I would suggest using the class property (but probably not private, which I generally don't find much use for; protected is normally a better idea) as it's easier for testing later; you can't do anything to unset, alter or check the static variable.
I see some possible confusion in the other answers here between static variables and static class properties. PHP uses the same modifier, but the behaviour is quite different; an example follows.
<?php
class Foo {
// Static class property
public static $bar = 'bar';
public function blarg() {
static $bar;
if (empty($bar)) {
$bar = 'blarg';
}
return $bar;
}
}
In the above example the static class property can be accessed using Foo::$bar (or self::$bar within the class and static::$bar in PHP 5.3); the static variable cannot and is only visible inside the function blarg().
Neither is "better". It would be like asking whether a screwdriver is better than a tenon saw.
The private variable in your first example will only be available to that instance of the class (although only to its methods). Create a new instance, and the variable can and will have a different value.
The static variable in your second example will be available to all instances of that class, admittedly only in that method. But set it one instance, and a second instance will see the same value.
I've been looking at some code and am having a hard time working out variable declaration in php classes. Specifically it appears that the code i'm looking at doesn't declare the class variables before it uses them. Now this may be expected but I can't find any info that states that it is possible. So would you expect this:
class Example
{
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
to work? and does this create these variables on the class instance to be used hereafter?
This works the same as a normal variable declaration would work:
$foo = 'bar'; // Created a new variable
class Foo {
function __construct() {
$this->foo = 'bar'; // Created a new variable
}
}
PHP classes are not quite the same as in other languages, where member variables need to be specified as part of the class declaration. PHP class members can be created at any time.
Having said that, you should declare the variable like public $foo = null; in the class declaration, if it's supposed to be a permanent member of the class, to clearly express the intent.
So would you expect this: (code sample) to work?
Yes. It's pretty bad practice (at least it makes my C++ skin crawl), but it wouldn't surprise me in the slightest. See example 2 in the following page for an example of using another class without declaring it beforehand. http://www.php.net/manual/en/language.oop5.basic.php It will throw an error if E_STRICT is enabled.
And does this create these variables on the class instance to be used hereafter?
Yep. Ain't PHP Fun? Coming from a C++/C# background, PHP took a while to grow on me with its very loose typing, but it has its advantages.
That's completely functional, though opinions will differ. Since the creation of the class member variables are in the constructor, they will exist in every instance of the object unless deleted.
It's conventional to declare class member variables with informative comments:
class Example
{
private $data; // array of example data
private $var; // main state variable
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
I know that you can call functions using variable names like this:
$foo = "bar";
function bar()
{
echo "test";
}
$foo(); // echos test
I am wondering if in a class, an actual function overrides that.
If I had this class:
class myClass{
public $test;
public function __construct()
{
$this->test = new myOtherClass;
}
public function test()
{
echo "foo";
}
}
Would both of these work correctly?
$obj->test(); // echo foo
$obj->test->method(); // access a method of myOtherClass
Edit: The original idea for this was that myOtherClass held a class with one main function that was accessed all the time, and a few other less accessed ones. I could use test() to link the main function to the class so there is less typing. But given the first answer I'll probably stick away from that.
I don't know PHP well enough to answer your question, but I spent several years maintaining products and would like to point out a serious difficulty with maintainability with this. Consider that you have the question as to whether this will even work properly. Now consider that the person maintaining your code will (a) have the same question as you and (b) probably not read the whole class (unless it's a very small class). And if you're changing $test from outside the class, it will be even more difficult to understand.
While this is an interesting question, especially from an academic point of view, it's a terrible practice from a maintenance point of view. Please use different variable names for different purposes; for example, use $otherClass for the pointer to the other class and test() for the test function and your maintainers (including yourself, if you maintain your own code) will curse at you less :)
PHP allows different symbols with the same name. Object properties and methods are totally different things in PHP, unlike JavaScript and some other languages:
// all of them work OK
define('SomeClass', 'SomeClass');
function SomeClass () {}
class SomeClass {}
This causes ugly problems in PHP 5.3:
$foo = new StdClass;
$foo->bar = function () {
return "bar";
};
$foo->bar(); // does not work, unfortunately :(
You wrote:
$obj->test(); // echo foo
$obj->test->method(); // access a method of myOtherClass
Right, this is how it works. You're not using anything variable in there.
$obj->test; // member variable $test of $obj
$obj->test(); // method test() of $obj
$obj->$test(); // variable function, result depends on content of $test
$obj->test()->otherTest(); // invokes otherTest() on an object
// returned by $obj->test()
$foo = 'test';
$bar = 'otherTest';
$obj->$foo()->$bar(); // same as above, but please, for the love of God,
// don't ever use this. ;)