My class structure is as follows,
Class Core{
public $Variable = "Test";
Class SubClass{
// functions, etc
}
// functions etc
}
I need to access the variable $Variable from within the SubClass class, but I cannot think of a way to do it. I have tried $this->this->Variable without success.
Edit While this is incorrect syntax, this is how my class system is setup (and is achieved using includes).
Assuming you had a proper inheritance model set up, you could use parent::. But your code as-is is a flat-out syntax error. You cannot nest classes like that.
Class Core {
public $var = 'test';
}
Class SubClass Extends Core {
function foo() {
$localvar = parent::$var;
}
}
comment followup:
Perhaps something more like this?
class Core {
public $Variable = 'foo';
function __construct() {
$this->subclass = new SubClass($this->variable);
}
}
class SubClass {
public $coreVariable;
function __construct(&$var) {
$this->coreVariable = $var;
}
}
I am going to answer this because the previous comments show so much ignorance about how PHP works and the scope of variables when nesting Classes and functions which is perfectly fine to do in PHP. It happens a lot when using third party classes as includes in procedural code bases.
Class Core{
public $Variable = "Test";
Class SubClass{
// functions, etc
function new()
{
global $Variable;// this brings the variable into scope
echo $Variable;
{
}
// functions etc
}
Related
I've seen a few questions with really similar titles but they where irrelevant to my specific problem.
Basically, I want to access the variables from my core class in a class which extends core, but things seem to be quite complicated compared to other examples. I am using a MVC framework. I've simplified the code below to remove anything that was irrelevant.
index.php
// Load the core
include_once('core.php');
$core = new Core($uri, $curpath);
$core->loadController('property');
core.php
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once('controller/'.$name.'.php');
$controller = new $name();
}
}
property.php
class Property extends Core
{
function __construct()
{
print $this->curpath;
}
}
Printing $this->curpath just returns nothing. The variable has been set but it is empty.
If I print $this->curpath inside core.php it prints fine.
How can I access this variable?
You are doing it wrong tm
You should be utilizing an autoloader, instead of including files with each class manually. You should learn about spl_autoload_register() and and namespaces, and how to utilize both of them.
Do not generate output in the __construct() methods. That's an extremely bad practice
The variables are still there. That is not the problem. In PHP, when you extend a class, it does not inherit the constructor.
You do not understand how inheritance works. When you call method on instance of extended class it will not execute parent class's method , before calling extended class's methods. They get overwritten , not stacked.
Object variables should not be exposed. You are breaking the encapsulation. Instead og defining them as public you should use protected.
You should extend classes of they are different type same general thing. The extends in PHP means is-a. Which means that, when you write class Oak extends Tree, you mean that all the oaks are trees. The same rule would mean, that in your understanding all Property instances are just a special case of Core instances. Which they clearly ain't.
In OOP, we have principle. One of which is Liskov substitution principle (shorter explanation). And this is the thing your classes are violating.
The problem, I think, lies here:
If you consider a simple inheritance like this one:
class Dog{
public $color;
public function __construct($color){
$this->color = $color;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
}
}
//Create Dog:
$alfred = new Dog('brown');
//Create TrainedDog
$lassie = new TrainedDog('golden',array('fetch'));
In this example $alfred is a brown dog and $lassie is a golden dog. The two instances are separate from each other, the only thing they have in common is that they both have a property called $color.
If you want a variable that is available in all Dogs for example, you need a class variable:
class Dog{
public $color;
public static $numberOfLegs; //Class variable available in every instance of Dog.
public function __construct($color, $numberOfLegs){
$this->color = $color;
self::$numberOfLegs = $numberOfLegs;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
echo parent::$numberOfLegs;
}
}
This does not make much sense in many cases though, because if you have two instances of the parent class (in you're case Core), they also share the class variable.
Unless you can ensure that Core is instanciated only once, this approach will not work. If it does only exist once, you can just as well use constant variables to store the 2 properties.
If there exist multiple instances/objects of Core, I'd recommend using a composition (as suggested by Alvin Wong).
class Core{
//Just as you programmed it.
}
class Property{
private $core;
public function __construct($core){
$this->core = $core;
echo $core->curPath;
}
}
Try this
include_once('core.php');
$core = new Core('test', 'path');
$core->loadController('property');
class Property extends Core
{
function __construct($date)
{
print $date->curpath;
}
}
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once($name.'.php');
$controller = new $name($this);
}
}
I have a class like this:
class A {
public $var = "";
function __construct() {
$this->var = "value";
}
}
And a child class like this:
class B extends A {
function __construct() {
// Is this correct?
parent::__construct();
}
function my_function() {
// Or this?
// $options is an instantiation of A.
global $options;
echo $this->var;
}
}
The problem I was having is that when I called the my_function() method, the value of var was empty. After reading on php.net for a while I found out that when a child class has its own constructor, the parent constructor is overridden which is why my variable was empty. My question is if the way I'm calling parent::__construct() is the right solution or if I should just globalize the instantiated object that I created in my script? I've done a lot of reading in comments on PHP.net and other places and I couldn't find anything concise.
With parent::method() you call the overridden method (not only the constructor), so your solution is the right one. In your case you can omit the constructor completely and just set the value, when you declare the property.
class A {
public $var = "value";
}
Additional: Global variables are ugly in every way. Use them only, if you have really good reasons to do so and never, because its more convenient.
The following "implementation" ...
$instanceOfB = new B();
$instanceOfB->my_function();
results in "value" ... as excpected.
What has been your way of calling my_function() ?
I wish there was a sub keyword that would make the code below print value on execution. There isn't though and I wonder - is there an existing way to refer to a member of a subclass?
class Main
{
static function foo()
{
echo sub::$variable;
}
}
class Sub extends Main
{
static $variable = "value";
}
Sub::foo();
I think you are looking for static::$variable. That's called Late Static Binding and is available as of PHP 5.3.
So this might sound a little convoluted. Fingers crossed I come across clearly.
I'm working in an MVC framework in PHP.
I load a controller /report/index which calls to a helper
<? class ReportController extends Controller {
public function index() {
$foo = MainReport::get_data($_REQUEST);
}
}
?>
Inside the helper
<? class MainReport extends foo {
public function get_data($_REQUEST) {
// do stuff
return $stuff_done;
}
}
?>
It I run it like ^this all's well and good. Unfortunately, I want to run it like this:
<? class MainReport extends foo {
private function do_stuff() {
// do even better stuff here!
return $better_stuff;
}
public function get_data($_REQUEST) {
// do stuff
$x = $this->do_stuff();
}
}
?>
Unfortunately... when I try and call a private function from within a class that I've called from elsewhere... (whew, that's a mouthful) ... everything dies. Dies so very very badly that I don't even get an error.
It seems obvious to me that I'm having an incredibly dorky sort of syntax issue of some sort... but how do I correctly access private functions from within a class?
Maybe something like:
self::do_stuff();
What about declaring and accessing private class variables?
private $bar = array();
Any help would be welcome.
You are calling your function from a static context,
MainReport::get_data($_REQUEST)
therefore $this does not exist while inside that function.
If you want to call another class function while inside a static context, you have to also call it statically.
i.e.
public function get_data($_REQUEST) {
// do stuff
$x = MainReport::do_stuff();
}
Alternatively, you can create an instance of your class in the original call and use the instance:
$myMainReport = new MainReport();
$myMainReport->get_data($_REQUEST);
Then your class code will work as expected
I've just found that self:: does work as well
if I want to have private class variables, I can declare and access them using
private static $foo
and
self::$foo = "foo";
additionally a private function can be accessed with
self::function_foo();
I have a variable on the global scope that is named ${SYSTEM}, where SYSTEM is a defined constant. I've got a lot of classes with functions that need to have access to this variable and I'm finding it annoying declaring global ${SYSTEM}; every single time.
I tried declaring a class variable: public ${SYSTEM} = $GLOBALS[SYSTEM]; but this results in a syntax error which is weird because I have another class that declares class variables in this manner and seems to work fine. The only thing I can think of is that the constant isn't being recognised.
I have managed to pull this off with a constructor but I'm looking for a simpler solution before resorting to that.
EDIT
The global ${SYSTEM} variable is an array with a lot of other child arrays in it. Unfortunately there doesn't seem to be a way to get around using a constructor...
Ok, hopefully I've got the gist of what you're trying to achieve
<?php
// the global array you want to access
$GLOBALS['uname'] = array('kernel-name' => 'Linux', 'kernel-release' => '2.6.27-11-generic', 'machine' => 'i686');
// the defined constant used to reference the global var
define(_SYSTEM_, 'uname');
class Foo {
// a method where you'd liked to access the global var
public function bar() {
print_r($this->{_SYSTEM_});
}
// the magic happens here using php5 overloading
public function __get($d) {
return $GLOBALS[$d];
}
}
$foo = new Foo;
$foo->bar();
?>
This is how I access things globally without global.
class exampleGetInstance
{
private static $instance;
public $value1;
public $value2;
private function initialize()
{
$this->value1 = 'test value';
$this->value2 = 'test value2';
}
public function getInstance()
{
if (!isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class();
self::$instance->initialize();
}
return self::$instance;
}
}
$myInstance = exampleGetInstance::getInstance();
echo $myInstance->value1;
$myInstance is now a reference to the instance of exampleGetInstance class.
Fixed formatting
You could use a constructor like this:
class Myclass {
public $classvar;
function Myclass() {
$this->classvar = $GLOBALS[SYSTEM];
}
}
EDIT: Thanks for pointing out the typo, Peter!
This works for array too. If assignment is not desired, taking the reference also works:
$this->classvar =& $GLOBALS[SYSTEM];
EDIT2: The following code was used to test this method and it worked on my system:
<?php
define('MYCONST', 'varname');
$varname = array("This is varname", "and array?");
class Myclass {
public $classvar;
function Myclass() {
$this->classvar =& $GLOBALS[MYCONST];
}
function printvar() {
echo $this->classvar[0];
echo $this->classvar[1];
}
};
$myobj = new Myclass;
$myobj->printvar();
?>
The direct specification of member variables can not contain any references to other variables (class {public $membervar = $outsidevar;} is invalid as well). Use a constructor instead.
However, as you are dealing with a constant, why don't you use php's constant or class constant facilities?
You're trying to do something really out-of-the-ordinary here, so you can expect it to be awkward. Working with globals is never pleasant, especially not with your dynamic name selection using SYSTEM constant. Personally I'd recommend you use $GLOBALS[SYSTEM] everywhere instead, or ...
$sys = $GLOBALS[SYSTEM];
... if you're going to use it alot.
You could also try the singleton pattern, although to some degree it is frowned upon in OOP circles, it is commonly referred to as the global variable of classes.
<?php
class Singleton {
// object instance
private static $instance;
// The protected construct prevents instantiating the class externally. The construct can be
// empty, or it can contain additional instructions...
protected function __construct() {
...
}
// The clone and wakeup methods prevents external instantiation of copies of the Singleton class,
// thus eliminating the possibility of duplicate objects. The methods can be empty, or
// can contain additional code (most probably generating error messages in response
// to attempts to call).
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
//This method must be static, and must return an instance of the object if the object
//does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
//One or more public methods that grant access to the Singleton object, and its private
//methods and properties via accessor methods.
public function GetSystemVar() {
...
}
}
//usage
Singleton::getInstance()->GetSystemVar();
?>
This example is slightly modified from wikipedia, but you can get the idea. Try googling the singleton pattern for more information
I'd say the first two things that stand out to me are:
You don't need the brackets around the variable name, you can simply do public $system or public $SYSTEM.
While PHP may not always require it it is standard practice to encapsulate non-numeric array indexes in single or double quotes in case the string you're using becomes a constant at some point.
This should be what you're looking for
class SomeClass {
public $system = $GLOBALS['system'];
}
You can also use class constants which would instead be
class SomeClass {
const SYSTEM = $GLOBALS['system'];
}
This can be referenced within the class with 'self::SYSTEM' and externally with 'SomeClass::SYSTEM'.