Write what is best and why?
class Chat
{
private $_couleur;
private $_race;
function __construct($couleur, $race)
{
$this->_couleur = $couleur;
$this->_race = "$race";
}
public function getCouleur() {
return $this->_couleur;
}
}
Or
class Chat
{
function __construct($couleur, $race)
{
$this->_couleur = $couleur;
$this->_race = "$race";
}
public function getCouleur() {
return $this->_couleur;
}
}
Because $this->_couleur is initialized when the class is instancied, so declare the property directly in the class is useless, isn't ?
Declaring the variables at the top of your class is a very good practice, because it makes it clear to anyone that reads your code which properties the class has private and which properties the class has public.
In the second example your variables will be public because they're dynamically generated.
When your constructor would be much bigger it is a pain in the ass as developer to find out where your variables are introduced.
It is also good to set default values (if they are always the same) to the variables in the class as opposed to the constructor. It makes your code more readable and understandable.
First block of code is better from the second, But one thing in first block.
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
This code collected from php.net
<?php
class Test
{
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
private function bar()
{
echo 'Accessed the private method.';
}
public function baz(Test $other)
{
// We can change the private property:
$other->foo = 'hello';
var_dump($other->foo);
// We can also call the private method:
$other->bar();
}
}
$test = new Test('test');
$test->baz(new Test('other'));
?>
Output:
string(5) "hello"
Accessed the private method.
The first one is better. You are actually declaring your variables as private, giving them a meaningful scope. The second version is more error-prone.
Just wanted to add one simple benefit of declaring class properties: Any good IDE will parse and build a symbol table out of your declared class properties. So if you are writing a class and start typing $this->, a list of your declared properties will show up so you can easily select the one you want to use. If you create variables in your constructor without declaring them, your IDE won't be able to see them.
Related
Is it possible to dynamically extend a class object in PHP? And what would be the most elegant way of doing this?
Some example code for further explanation:
class BasicClass {
private $variable;
public function BasicFunction() {
// do something
$this->variable = 10;
}
}
class ExtendedClass extends BasicClass {
public function ExtendedFunction() {
// do something else with basic class variable
return $this->variable/2;
}
}
$A = new BasicClass();
If(condition for extension){
// A should be of class ExtendedClass
// and the current class variables should be kept
// ... insert the magic code here ...
// afterwards we would be able to use the ExtendedFunction with the original variables of the object
$A->ExtendedFunction();
}
One way of tackling this would be creating a new object of ExtendedClass and copying all the variables from the old object. But can this be done more elegantly?
Yes. It is possible. One way to do it would be using anonymous classes or simply overwriting the class itself(in your case $A) but that implies a little more logic and it's not as clean, so I won't get into it.
NOTE: Support for anonymous classes was added in PHP 7.
Using your example above we can compose the following code(I changed the visibility of the property in order to be able to use it in the extended class. I'd suggest you add a getter rather than changing the visibility).
class BasicClass {
public $variable;
public function BasicFunction() {
// do something
$this->variable = 10;
}
}
class ExtendedClass extends BasicClass {
public function ExtendedFunction() {
// do something else with basic class variable
return $this->variable / 2;
}
}
$A = new BasicClass();
if (TRUE) {
// A should be of class ExtendedClass
$A = new class extends ExtendedClass {
};
$A->ExtendedFunction();
}
Do note that this will overwrite $A. You'll still have all the available methods in it since inheritance is not lost by doing this.
Obviously whichever approach you take won't be the cleanest way you can do this.
My answer stands, but if you were to edit your question and provide more details on what it is you want to actually achieve by doing this perhaps a different approach is more suitable.
You can also achieve some magic using eval and possibly Reflection, but they're so magically magic I refuse to write the answer since it promotes such bad practices.
I have a strange behavior in my php 5.3
i have a class wich dous this in a function
$new = new self($data);
$new->setServiceManager($this->service);
$new->cacheInstance();
BUT the function cacheInstance is a private function....
private function cacheInstance()
{
foreach ($this->data as $name => $class) {...}
}
Can some one give an explanation why the hell can this be used like this? shouldn`t this method be private aka unaccessible from outside?
UPDATE:
ok now im totally lost... i can even acess the private variables of the instance... like what the ... this has to be some intended behavior, can somone point me in a direction?
If you can create a class instance with new self() it means you are in the class, and of course you can access private properties an functions. This snippet is taken from the PHP Docs (link)
/**
* Define MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private
IN YOUR CASE:
class Cache {
private $service = null;
private function cacheInstance()
{
foreach ($this->data as $name => $class) {}
}
public function setServiceManager( $service ) {
}
public function myTest( $data ) {
$new = new self( $data );// you are in the class, so you can call new self()
$new->setServiceManager($this->service);
$new->cacheInstance();
}
}
$cache = new Cache();
$cache->service; //Fatal error: Cannot access private property
$data = array();
$cache->myTest( $data );// working
$cache->cacheInstance();// not working
private, protected and public accessibility works on class level, not on object level.
While it may seem counter intuitive first, this is not your usual PHP weirdness.
It's the same in other OOP languages, like Java
Note that accessibility is a static property that can be determined at compile time; it depends only on types and declaration modifiers.
and C#
The private keyword is a member access modifier. Private access is the least permissive access level. Private members are accessible only within the body of the class or the struct in which they are declared
(highlights added)
Explanation
The accessibility is a mechanism to hide implementation details from code in other classes, not for encapsulation of objects. Or as it's stated in the Java specs, accessibility can be determined at compile time, i.e. there cannot be a runtime violation because it's a different object.
It makes sense, if you look at the difference between private and protected. For private members, an object does not have access to its own members if they are declared in a parent class. Sounds weird? That's because the terminology is wrong. The class does not have access to privates of its parent class (i.e. it may not use them).
Now in your method, you use private variables within the same class. There is no need to hide this implementation detail from yourself, the author of this class, no matter what the objects are at runtime.
ok... wierd like quantum mechanics... have been pointed in RL to the answer
http://php.net/manual/en/language.oop5.visibility.php
QUOTE:
Objects of the same type will have access to each others private and
protected members even though they are not the same instances. This is
because the implementation specific details are already known when
inside those objects.
Talking about wierd...
As I am new to php oop I have a question how do I use global variables inside a static class with out using the constructor? Or must I use in this case a constructor?
$varGlob = 'hello mars';
class statclass {
global $varglob;
protected static $newVar = $varglob;// not going to work
static public function outputfunc(){
return statClass::$newVar;
}
}
You don't use global variables in a PHP class, but static variables. Although this seems confusing, global's aren't meant to be used in object-oriented PHP, but rather 'normal' PHP, old style.
See: http://nl3.php.net/manual/en/language.oop5.static.php for more information.
As Gordon mentioned you should not make use of globals or the thing I suggested because that will break your OOP design. You actually should pass the value through constructor [That's why they are meant for ]
However, the below code solves your purpose by making use of named constant such as define , Sadly this is an ugly-way...
<?php
define("varGlob","hello");
class statclass
{
protected static $newVar = varGlob;
static public function outputfunc(){
return statClass::$newVar;
}
}
echo statclass::outputfunc(); //"prints" hello
Alternate way.. (Recommended)
<?php
class settings
{
# Populate all your variables that are to be used.
protected $var1='Variable1';
protected $var2='Variable2';
}
class yourclass extends settings
{
# All those variables used in the class `settings` can be accessed here.
public function disp()
{
echo $this->var1;
}
}
$yc = new yourclass;
$yc->disp(); //"prints" Variable1
I'm struggling to find a correct approach to pass data between classes, which do not directly call each other, and are only related through a parent class (which I now use, but I consider it a dirty workaround rather than anything near a solution).
I have 3 classes both able to read input and write output, and based on configuration I set one to read, another one to write. It may even be the same class, they all share a parent class, but they are always two separate instances called from a controller class.
Currently I use this sort of functionality:
class daddy {
public static $data;
}
class son extends daddy {
public function setData() {
parent::$data = "candy";
}
}
class daughter extends daddy {
public function getData() {
echo parent::$data;
}
}
while($processALineFromConfig)
$son = new son;
$son->setData();
$daughter = new daughter;
$daughter->getData();
daddy::$data = null; //reset the data, in the actual code $daughter does that in parent::
}
Instantination of these classes runs in a loop, therefore I always need to reset the data after $daughter receives them, 'cos otherwise it would stay there for another pass through the loop.
I'm absolutely sure it's not how class inheritance is supposed to be used, however I'm struggling to find a real solution. It only makes sense the data should be stored in the controller which calls these classes, not the parent, but I already use return values in the setter and getter functions, and I am not passing a variable by reference to store it there to these functions 'cos I have optional parameters there and I'm trying to keep the code clean.
What would be the correct approach to pass data through the controller then?
Thanks!
The best option would be for two object share some other, third object. This would be the class for "third object" which will ensure the exchage:
class Messenger
{
private $data;
public function store($value)
{
$this->data = $value;
}
public function fetch()
{
return $this->data;
}
}
Then a class for both instance, that will need to share some state:
class FooBar
{
private $messenger;
private $name = 'Nobody';
public function __construct($messenger, $name)
{
$this->messenger = messenger;
$this->name = $name;
}
public function setSharedParam($value)
{
$this->messenger->store($value);
}
public function getSharedParameter()
{
return $this->name . ': ' . $this->messenger->fetch();
}
}
You utilize the classes like this:
$conduit = new Messenger;
$john = new FooBar($conduit, 'Crichton');
$dominar = new FooBar($conduit, 'Rygel');
$dominar->setSharedParameter('crackers');
echo $john->getSharedParameter();
// Crichton: crackers
Basically, they both are accessing the same object. This also can be further expanded by making both instance to observe the instance of Messenger.
The only object oriented programming experience I have is from C#, so PHP is throwing me some curve balls I could use some help with.
I have a class I use for all my pages, the "pagebase" if you will. It handles the lowest level html structure. That class is inherited by several other classes. Those classes are the different page types the site has. Now: I'm having trouble setting a variable in the "pagebase" from the instance of the class that inherits it. In C# that would be no problem seeing as the class instance behaves as if it were the inherited class.
This is a representation of what I've got:
pagebase.php
<?php
class pagebase
{
var $title = "No title";
var $body = "<center>No content</center>";
function setTitle($value) {
$this->title = $value;
}
function setBody($value) {
$this->title = $value;
}
function updateHTML()
{
...
}
function drawPage()
{
$this->updateHTML();
echo $this->html;
}
}
?>
std_page.php
<?php
include("includes/pagebase.php");
class std_page extends pagebase
{
function std_page()
{
...
}
function updateHTML()
{
parent::setBody(
"
<div id=\"main_wrapper\">
The page goes here!
</div>
"
);
}
function drawPage()
{
$this->updateHTML();
parent::drawPage();
}
}
?>
index.php
<?php
include "includes/std_page.php";
$page = new std_page;
$page->setTitle("Avesta");
$page->drawPage();
?>
Now among other things, the biggest problem here is that NOTHING WORKS. The values in pagebase aren't changed even though I'm getting no error indicating the function wasn't found or run in any shape, way or form.
Someone please just inform me what I'm doing wrong - Thanks
First thing first, never declare your properties using var keyword, please define its accesibilty using public, private, or protected.
Then when you want to access properties or method from the child class, you just need to use $this keyword. e.g $this->title, $this->setTitle('title')
Then there is static keyword when you define property or method as static you call it using :: operator. e.g if you have public static $title then you can access that using pagebase::$title
Hopes it clear some confusion.
This is a case of parent working in static scope, which is why you're using the :: operator.
If it's inheritance, just try $this->setBody for example.
I've made some changes to make the code run and fix up some issues. It's still not ideal, but it should work and be instructive...
abstract class pagebase
{
private $title = 'No title';
private $body = 'No content';
public function setTitle($value) {
$this->title = $value;
}
public function setBody($value) {
$this->body = $value;
}
public function drawPage()
{
$this->updateHTML();
echo $this->body;
}
abstract protected function updateHTML();
}
class std_page extends pagebase
{
protected function updateHTML()
{
$this->setBody(
"
<div id=\"main_wrapper\">
The page goes here!
</div>
"
);
}
}
Here are the changes:
I made pagebase abstract, with updateHTML an abstract method. It makes no sense to render a pagebase, and the way a particular child class expresses its individuality is by creating its own version of the updateHTML method.
I made your internal variables private, meaning outside code (including child classes like std_page) can't modify or read them. If child classes need access, you can use protected instead. Those methods accessible from anywhere are public. See visibility in the manual.
When accessing methods defined in the parent, you don't need parent::. That's only required when the child has its own implementation that overrides the parent's, but you want to call the parent's version explicitly. This can be helpful if the parent method does some real work, and the child wants to build off of that. See example number 3 in this manual entry.
If you're not changing how drawPage works, there's no need to redefine the method. Since you are overloading updateHTML, that overloaded version automatically gets used in the existing implementation of drawPage.
I fixed a copy and paste error where your setBody method actually set your title, and you were using $html in some places where presumably you meant $body.