There is a php class in which I like to change the variable, but I can't make it happen.
The Class:
class ShopCart
{
private $maincurrency = 'USD';
private function set_Currency() {
$maincurrency = 'GBP';
return $maincurrency;
}
}
This doesn't work. Even if I make it public. What am I doing wrong?
You have to use $this->maincurrency in the body of your method. Your current code creates and sets local variable, not a member.
You need $this:
class ShopCart {
private $maincurrency = 'USD';
private function set_Currency() {
$this->$maincurrency = 'GBP';
return $this->$maincurrency;
}
}
Otherwise you're creating a new variable local to the function and just using that.
The manual does actually tell you this already:
Within class methods the properties, constants, and methods may be
accessed by using the form $this->property (where property is the name
of the property) unless the access is to a static property within the
context of a static class method, in which case it is accessed using
the form self::$property.
The documentation is your friend; consult it before asking here please.
You may also want to consider not returning anything from a setter, though that's up to you. There are advantages to doing so, even if it's not all that conventional in PHP.
class ShopCart {
private $maincurrency = 'USD';
private function setCurrency() {
$this->maincurrency = 'GBP';
}
}
change $maincurrency = 'GBP'; to $this->maincurrency = 'GBP';,
and also return $this->maincurrency;
Related
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.
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...
Why can't I get access to my "incSessionCount" function inside my "newSession" function?
class Session {
private $_num_session = 0;
private function incSessionCount() {
$this->_num_session++;
}
public static function newSession($key, $value) {
if( !isset( $_SESSION[$key] ) ) {
$_SESSION[$key] = $value;
$this->incSessionCount();
return true;
} else {
return false;
}
}
}
I just played around, like making incSessionCount() public and so on...
And then I thought, that it must be even accessible, when it's set to private ...
It's possible, that I missed a useful article, which should have helped me, but finally I ended up asking.
So why doesn't this work?
The problem is that your newSession is static, thus you are not supposed to call instance methods from it.
I suppose you're trying to do:
Session::newSession($key, $value);
instead of
$session = new Session();
$session->newSession($key, $value);
The error is not because you're calling a private method from within a public one, but because you're using $this instead of self.
$this special variable represents the current instance object while self represents the class itself.
If you enable error display and set error reporting level to E_ALL, you will see the problem is about using $this in a wrong context.
See below theses little modifications to do what you want, and check theses pages about
class Session {
private $_num_session = 0;
private static $inst = null;
public static function instance(){
if (!static::$inst)
static::$inst = new Session();
return static::$inst;
}
private function incSessionCount() {
$this->_num_session++;
}
public static function newSession($key, $value) {
if( !isset( $_SESSION[$key] ) ) {
$_SESSION[$key] = $value;
Session::getInstance()->incSessionCount();
return true;
} else {
return false;
}
}
}
You can look for design pattern and singleton on internet, and use magic __clone() to forbid more than one instance
I only found the german version of the documentation, I don't know why : http://de.php.net/manual/de/language.oop5.patterns.php
EDIT: Check this link about design patterns : http://www.phptherightway.com/pages/Design-Patterns.html
Remember, that static methods are binded with the class. Non-static methods are binded with the instance (when you do something like $instance = new MyClass();). But when you call something on the static context, you don't have to have any instance.
It's the same, when you want to call something on instance($this), because in static context doesn't exist any instance.
The problem is the public method is static and you are trying to use a method for an instantiated object. In a static method the $this variable refers to other static methods and properties only.
I am creating my own MVC framework, just to learn something new and ran into this problem recently.
Lets say I have like this:
Class Post extends \application\BaseClass
{
private $objPostDetail = null;
private $objAuthor = null
private $objCategory = null;
private $objType = null;
private $objTitlePicture = null;
public function __construct(PostDetail $objPostDetail,
Author $objAuthor,
Category $objCategory,
Type $objType,
TitlePicture $objTitlePicture)
{
$this->objPostDetail = $objPostDetail;
$this->objAuthor = $objAuthor;
$this->objCategory = $objCategory;
$this->objType = $objType;
$this->objTitlePicture = $objTitlePicture;
}
}
Then some objects used in the constuctor can also be comlex to create.
I get data for it from PostDAO class, which returns array of data.
Now the problem is how to create new instance of this class, since it may be on many places in the application.
I think create everywhere $objAuthor, then $objCategory etc. to finally create $objPost is not good. So I created what I think may be called a Factory:
Class PostFactory extends \application\BaseFactory
{
private $arrData = null;
private $objPostDetail = null;
private $objCategory = null;
private $objType = null;
private $objTitlePicture = null;
public function __construct($arrData)
{
$this->arrData = $arrData;
}
public function build()
{
$this->objPostDetail = $this->buildPostDetail();
$this->objCategory = $this->buildCategory();
$this->objType = $this->buildType();
$this->objTitlePicture = $this->buildTitlePicture();
return $this->buildPost();
}
private function buildPostDetail()
{
$objPostDetail = new \includes\classes\factories\PostDetailFactory($this->arrData);
return $objPostDetail->build();
}
private function buildCategory()
{
$objCategory = new \includes\classes\factories\CategoryFactory($this->arrData);
return $objCategory->build();
}
private function buildType()
{
$objType = new \includes\classes\factories\TypeFactory($this->arrData);
return $objType->build();
}
private function buildTitlePicture()
{
$objTitlePicture = new \includes\classes\factories\TitlePictureFactory($this->arrData);
return $objTitlePicture->build();
}
private function buildPost()
{
return new \includes\classes\Post($this->objPostDetail, $this->objCategory,
$this->objType, $this->objTitlePicture);
}
}
It works well, but I don't like that I have twice as much classes and I don't know what parameters do I need for instantiating Post since I pass array to the Factory class (because I want to avoid many parameters in the constructor).
So, my question is what is the best way how to create an instance of class like this?
Thanks in advance for any help.
If you want to create your own MVC framework, I strongly suggest starting with some sort of "Container" which holds instances of service classes (classes that only have to be initialized once, for example Request or Response).
Use reflection classes to automatically inject the parameters a constructor needs by iterating over the function arguments of the constructor.
See the following example of an idea I usually use. It's very reliable and reasonably fast. If your framework has a LOT of different classes and you depend on this functionality a lot, I strongly recommend implementing some way of caching the parameter lists from the reflection classes.
<?php
class SomeClass
{
public function __construct(Request $request, Response $response, $title = '')
{
echo get_class($request);
// will output "Request"
echo $title;
// will output "Hello World"
}
}
// This function will handle the dynamic dependency injection to make sure the constructor gets the arguments passed that it needs, with optional named arguments passing.
$some_class = YourFrameworkDispatcherClass->createInstance('SomeClass', array('title' => 'Hello World'));
?>
I've actually written a blog post about this on my blog. http://harold.info/engineering/php-dynamic-dependency-injection/
I think this can help you out with this structural problem.
I'm new to DI ,using Pimple. Using: php 5.3.5 (wamp), namespaces as well.
I'm refactoring code, using it, but came to a problem (s):
I have my Container that extends from Pimple, lets call it PContainer.php:
class ReuseableContainer extends Pimple{
private function initOutterClass(){
$this['special_location_class'] = '\SpecialLocation';
$this['special_location'] = function($c){return new $c['special_location_class']($c['location_details'],$c['location']);};
}
private function initGlobalFunctions(){
$this['getGeneralDataFromArray'] = function($c){
// returning a function
return function($arr){
foreach ($arr as $key => $value){
// do something
$new_data = $c['general_data_type'];
$new_data->id = $value['id'];
$new_data->name = $value['name'];
}
}
}
public function __construct(){
$this['location_class'] = '\Location';
$this['location_details_class'] = '\LocationDetails';
$this['general_data_type_class'] = '\GeneralDataType';
// define some objects
$this['location'] = function ($c) {
return new $c['location_class']();
};
$this['location_details'] = function ($c) {
return new $c['location_details_class']();
};
$this['general_data_type'] = function ($c) {
return new $c['general_data_type_class']();
};
$this->initOutterClass();
$this->initGlobalFunctions();
}
}
global $container ;
$container = new Pimple();
// embed the SomeContainer container
$container['embed'] = $container->share(function () { return new ReuseableContainer(); });
Ok. So i got a SpecialHelper.php which holds:
final class SpecialLocation{
public $name;
public $location;
public $picture;
public function __construct($location){
$this->location; // dependent on class: Location
}
}
final class SpecialUser{
private $id;
private $location;
public function __construct(\Location $location,$id=''){
$this->id = $id;
$this->location = $location; // $container['embed']['location'];
}
and we got our GeneralHelper.php which holds:
final class Location{
public $lat;
public $lng;
public function __construct($lat='',$lng=''){ $this->lat = $lat; $this->lng = $lng;}
}
final class LocationDetails{
public $id;
public $addresss;
public function __construct($id='',$address=''){$this->id = $id; $this->address = $address;}
}
class GeneralDataType{
public $id;
public $name;
public function getName(){ return $this->name;}
public function getId(){ return $this->id;}
}
and we have our "Special Class" controller, which looks something like this:
final class SpecialController{
public function foor($some_array){
$this->doSomething($some_array);
}
private function doSomething($ret_value){
// do something
$arr = array();
foreach($ret_value as $key => $value){
$something = $container['embed']['getGeneralDataFromArray']($value);
$special_location = $container['embed']['special_location'];
$arr[] = special_location;
}
return $arr;
}
}
Finally we have our main "driver", main.php
require('PContainer.php');
....
...
$some_array = array(....);
$special_controller = new SpecialController();
$special_controller->foor($some_array);
Problems:
1) I had to add initOutterClass function inside ReuseableContainer to decouple the "Special" classes, how could have i decoupled them in a better way? creating a new "special" 9container or something? as EVERYTHING now sitts inside the container.. same goes to the initGlobalFunctions()
2) regarding SpecialHelper.php: i have there SpecialLocation, which one of its properties is a \Location class, i've put it in the constructor , but if i have 20 object properties that are dependent, i must put them all as INPUT params for the constructor?? same goes to the SpecialUser class, it has a $location which if i could i would have made $this->location = $container['embed']['location']; instead of $this->location = $location; resulting in a dependent on the DI! :/
3) I've had to create SpecialHelper.php in a different file, despite wanting to put it in the "special class controller", just so there won't be any unknowns (due to require statement order)
4) MOST importantly: about the "Special class" controller, how do i solve the doSomething method? i must create "Special Location" object inside the loop but i get that $container is unrecognized (despite being global, as of scope probably) but more over it's really dependent! and it's a private function, i don't wish to pass the container to EVERY class i'll use from now on, it isn't IoC right?
Any help is appriciated... i'm trying to understand the best practices..
Thank you
4)Most important: IoC is correct. That an implementation is not correctly working does not reflect the principle of IoC itself.
If you want to use the global $container within a function, then should you use the global keyword within that function. That is how PHP works. Making it static is solving the problem of reference, but does not make a real difference.
An IoC container resolves the dependencies for the caller. The caller does not have to know anything about the internals of the callee - and he doesn't care either. So, there should be some kind of contract by which the exchange of data is regulated. If you have that situation, then you have IoC.
3)That problem is too vague to answer, but imo also not relevant from a practical perspective. Does it work? Ok, good to know. :-)
2)The clue of IoC is the use of contracts. The IoC container is there to connect the caller to the proper contract. The contract resolves to a concrete callee. The callee will return information inline with the contract. The caller understands the answer. Therefor will you need that the input and output in this process is independent of a certain implementation at a certain time. So don't use 20 object properties as input, but use an array or general object instead.
1) I get the idea that you are mixing functional flow (data flow) with technical flow (relationships between classes). An IoC container serves the purpose of the technical flow, it optimizes the dependency in the relationships between classes. For instance, if you want to connect to a database, then might you reuse an existing connection instead of creating new connections all the time. Or if you want to use a special functionality on several moments in your flow, then might you use IoC for that.