Why we can instantiate non-exist variable? What's the different when declare all properties on class and then assign value to it.
class hello {
public function __construct($db) {
$this->db = $db;
}
public function set($db) {
$this->db = $db;
}
public function get() {
return $this->db;
}
}
This isn't quite the same as using a non-existent variable - a non-existent variable will raise a notice in PHP. In your case, $this already exists, so setting a property on it just quietly creates a public property for your object. It's rather like an array that you add a new key-value pair to - you wouldn't expect that to raise a notice either.
If you know beforehand what properties you need, then yes, do declare them explicitly. In this case, you would probably want this to be protected, which you don't get if you don't declare. (Often people use private here, which means that a child class cannot access the property - though that's okay if you want to force descendants to use the getter).
The flexibility to add properties to objects can be useful if you don't know in advance what properties you'll want to store. For example, some ORMs use one class for all tables, and an instance of that class is used to store the column-value pairs for a row.
Related
I just started learning OOPS in php. I wrote a simple program for implementing inheritance. I am getting a fatal error of $this when not in object context. Can anyone explain me this error, what does it mean?
here is my code:
<?php
class human{
public $gender;
public function _construct($gender)
{
$this->gender=$gender;
echo $this->get_gender();
}
public function get_gender()
{
return $this->gender;
}
}
class person extends human{
public $name;
public $surname;
public static function set_name($name)
{
$this->name=$name;
}
public static function set_surname($surname)
{
$this->surname=$surname;
}
public static function get_name()
{
return $this->name;
}
public static function get_surname()
{
return $this->surname;
}
}
$john = new person('male');
$john->set_name('John');
$john->set_surname('Williams');
echo $john->get_name().' '.$john->get_surname().'is a '.$john->get_gender();
?>
There are two problems here:
You have defined your methods as static. You should not do that as they are not, they depend on being called on an object as you want to use the objects non-static properties.
You have a typo in your constructor function. The correct name for the constructor is __construct, notice the two _ at the beginning.
In a static function, $this does not exist. You can refer to the class itself with self::. So, instead of $this->surname, use self::surname. As noted below, this will change your error to a new error as it requires the variables to be declared static as well.
Of course, you really need to figure out WHY you made those functions static. Should they be static?
You're trying to access the $this property from a static method. You cannot do this, as anything static can be accessed without instantiating the class, therefore the $this variable would not make sense, as you are not in an actual class instance.
The this keyword refers to the current object you are working with, e.g. if you were to make 5 instances of person, each $this would refer to that specific instance of person, and you could change each objects properties freely.
When you use static you are not referring to any instance, you are simply accessing static variables and calling static methods of that class. All these variables and methods are 'class wide'. That means if you change the static property in one instance of the class, the static property will change in all the classes.
Another way to imagine this is, take when calling the new keyword, you create a new instance of the object. Every instance will have its own copy of all the properties and methods you describe in the class, EXCEPT for the static ones. Imagine that when you access a static method or a static property you are accessing one object always.
That's why it would not make sense to access $this from a static context. You are not referring to any specific instance, only the class itself.
I hope I've explained this well enough, it's a very important concept to grasp in OOP, and it does give some people a lot of trouble to understand the concept.
I understand you cannot duplicate constant. I am just confused as to why it does not work with different objects.
In one of my project I used them to pass settings to my object.
Here is an example:
class someClass {
function __construct($config) {
define("PRIVATE_KEY", $config['private_key']);
}
}
and here is how I create the objects
$objectA = new someClass($config['A']);
$objectB = new someClass($config['B']); //ERROR!!
I get the error:
Constant PRIVATE_KEY already defined
Most people that get this error had included the same constant multiple times.
In My case they are being used in separate objects. I will add some check to make sure they are not being redefined. but I am still curious to know why this happening.
Aren't object disposed/destroyed when no longer used?
Yes, objects are destroyed at some point, but define declarations are global and persist until they are undefined. Your code is defining the same constant twice.
Private properties, static properties, or maybe class constants are more appropriate for what you're attempting to do since they are encapsulated within the object.
class someClass {
private $private_key;
// constructor
function __construct($config) {
$this->private_key = $config['private_key'];
}
}
What are you using PRIVATE_KEY for? Is it supposed to be an instance variable? If so, you shouldn't use define() because its scope is global. You could instead do $this->private_key = $config['private_key'].
Why does my function return null?
class TestClass2
{
private $test_var="value";
public function getVar(){
global $test_var;
return $test_var;
}
}
$myclass = new TestClass2();
var_dump($myclass::getVar());
Is there an other way to access variables, which are outside the function, other than passing it in as a parameter, or declaring it as global?
You do not need "global", you just need "$this->test_var" to access your private variable inside a method of your class (in your case, the "getVar" method).
As for calling the function, since it is not static, use "->".
class TestClass2
{
private $test_var="value";
public function getVar(){
return $this->test_var;
}
}
$myclass = new TestClass2();
var_dump($myclass->getVar());
Now that I'm pretty certain what you're asking, I'll go ahead and give you a full answer.
When you call a method, an invisible argument, called $this is passed to it. It is a pointer to your class. I'm not certain this is how it works in PHP, but it's how C++ does it so the behaviors should be similar.
So if you're inside a class's method and you want to access one of its properties, you could tell PHP to use the global scope to break outside of your method and into the class, but that's bulky, obnoxious, and can lead to some complications as your class gets more complex.
The solution is to use the reference to our class that PHP magically gives us. If you want to access $foo->bar inside $foo->getBar(), you can get $this->bar. A good way to think of it is that this is a variable that holds the name of your class.
An additional advantage of this is that, because we're in our class, private properties are visible. This means that $this->bar is valid, whereas $foo->bar isn't, assuming bar is private, of course.
So if we apply this to your code, it becomes a lot simpler and prettier to look at (by PHP standards):
class TestClass2
{
private $test_var="value";
public function getVar(){
return $this->test_var;
}
}
$myclass = new TestClass2();
$myclass->test_var; // Error
$myclass->getVar(); // Not an error
I've been programming in PHP for several years and I've only just recently begun to look at object oriented code. Now I understand classes and such:
class Myclass {
public function __construct() {
}
}
and all that good stuff... I also understand creating functions and calling in my index.php:
$someVar = new Myclass;
One thing I've been trying to understand, being that i've recently looked at codeigniter and I like one thing about it and want to try and accomplish the same thing without actually using codeigniter.
in code igniter they have the variable $this appear to be their class variable. But by using that, you're able to call from multiple classes all at once.. such as:
$this->load->module(); which is in one class file..
$this->db->query(); which is in another class file.
I've searched google for the last few days trying to figure out how to do this same thing where each class would have the correlation between them all allowing me to run $this->class_name->function_name in my projects instead of creating a new variable for each class or for the sake of a clean index file, having every function in a single class file.
Any information (aside from buy this book - as that isn't an option for me) is greatly appreciated and I will thank you now (and will probably thank you again later just for good measure).
I've been reading you and Phil's comments. First off, you can't use $this on index.php. $this can only be used in the context of an object. So you could do,
$someVar = new Myclass;
...
$someVar->db->something();
...instead.
I'm not entirely sure what you mean by "read classes," but you can assign members to MyClass exactly as Phil indicates:
class MyClass {
private $inj;
function __construct(Injected $inj) {
$this->injected = $inj;
}
}
Note that the private $inj declaration is not mandatory, but skipping it is dangerous. Any non-declared members added are automatically public, and this can potentially screw with you if you rely on magical get. I would declare the properties you need.
Finally, you either need to include all class definitions you will use, use a function like load_class(), or use autoloading. If Injected above is not a declared class, you will get an error when trying to create one. load_class() almost certainly includes the class definition somehow.
The load and db references are class properties which are themselves other objects with public module() and query() methods respectively. For example
class MyClass
{
/**
* #var CI_DB
*/
private $db;
/**
* #var Loader
*/
private $load;
public function __construct(CI_DB $db, Loader $load)
{
$this->db = $db;
$this->load = $load;
// PHP also allows you to add arbitrary object properties
// that receive a "public" visibility
// Please note, this is not a good practice
$this->foo = new Foo;
}
public function someMethod()
{
$this->load->module();
$this->db->query();
// You can also use foo even though it is not defined
// in the class properties
$this->foo->something();
}
}
See http://www.php.net/manual/en/language.oop5.properties.php
Adding the foo property like we did is dangerous. Because it receives the public visibility, it may be altered externally to the class.
$class = new MyClass($db, $load);
$class->foo = new Bar;
$class->someMethod(); // will break if Bar does not contain a something() method
If I create a registry object to store other objects and settings in like this...
$registry = Registry::getInstance();
And then create 2 other objects and pass the Registry object into them like this below...
$core = new core($registry);
$database = Database::getInstance($registry);
and then later in the script I add some objects to the Registry object...
// Store some Objects into our Registry object using a Registry Pattern
$registry->storeObject("database", $database);
$registry->storeObject("session", $session);
$registry->storeObject("cache", $cache);
$registry->storeObject("user", $user);
Will methods in the core and database objects that were created at the top, still have access to all the objects that I store into the registry even though the other objets were stored into the registry AFTER the core and database Objects were created?
yes they will, objects are passed by reference (in php >= 5) so, each variable will refer to the same underlying object.
in old php, you would need to pass by ref:
$obj->registry =& $registry;
function f(& $registry) { // $registry is a reference }
the key in php <5 is the ampersand syntax when assigning and in function declarations.
If its the same instance of the object, than yes - otherwise they'll have to use shared memory to pass the objects around or no, you won't have access to them.
However, I'd imagine your registry is a singleton right? So yes.
edit: maybe Im not understanding your question ....
Yes, they'll have access to these object, but IMO Registry isn't the best solution here - Context would be much better because it allows you to model each property. It also gives you 100% sure that when you call $registry->get('user') some User object will be returned.
Context is pretty similar to Registry:
class Context {
protected $database;
protected $user;
protected $logger;
public function setDatabse(PDO $database) {
$this->database = $database;
}
public function getDatabase() {
return $this->database;
}
public function setLogger(Logger $logger) {
if ($logger instanceof MySpecificLogger) {
// do sth
}
$this->logger = $logger;
}
// rest of setters/getters
}
And when you use it later:
$db = $contextObject->getDatabase();
When you use Registry you don't have 100% sure that $db is then an object of PDO (in this example) what might causes some problems in some situations.
No, not by default. Parameters are passed by value in PHP in almost every case. What you want is called "passing by reference", which you can read more about in the manual.