How can I store a model that was returned from $bean->box() in RedBean?
For example, the following code doesn't work (it just inserts an empty row):
class Model_Comment extends RedBean_SimpleModel {
public $message;
}
$bean = R::dispense('comment');
$model = $bean->box();
$model->message = "Testing";
R::store($model);
It works if I use $model->unbox()->message = "Testing", but that's probably gonna get annoying real quick...
Obviously the code above is just an example, I could just set the property message on $bean here, but I want to be able to box a bean and pass it to other methods.
Is this how it's supposed to work, or am I missing something here?
This turned out to be caused by a "gotcha" when dealing with PHP's "magic" getter- and setter methods __get() and __set().
Looking at the source code for RedBean_SimpleModel, it actually uses the magic __set() method to update its bean when setting a property.
Here's comes the gotcha, straight from the PHP documentation:
__set() is run when writing data to inaccessible properties.
__get() is utilized for reading data from inaccessible properties.
__isset() is triggered by calling isset() or empty() on inaccessible properties.
__unset() is invoked when unset() is used on inaccessible properties.
So it turns out that __set() is never called for an existing (accessible) class member, i.e. public $message. So I could just remove all the public fields from the class and that would solve the problem, but then I'd lose all the autocomplete functionality and lint checking in my IDE.
So I came up with this solution instead:
class MyBaseModel extends RedBeanPHP\SimpleModel {
public function __construct(){
foreach( get_object_vars($this) as $property => $value ){
if( $property != 'bean' )
unset($this->$property);
}
}
}
class Model_Comment extends MyBaseModel {
public $message;
}
This effectively removes all member variables from the class MyBaseModel when it's instantiated, except $bean, which of course is a vital part of RedBeanPHP_SimpleModel.
Now I can easily subclass MyBaseModel and have all the public fields I need in my subclass models, and the code in the original question will work.
Related
This is one of those "my code works, I don't know why" times.
I have a method in an instantiated class that statically calls a method of what is basically a static class. I say "basically" because while coding it I neglected to declare the methods of the class exclusively static. The method in question belongs to the first class but I blindly copy/pasted the code (which was originally internal) and didn't quite update everything, so the $this-> remained even though the method doesn't belong to the class it's within.
So, basically I had this:
class MyClass{
public function callOtherMethod(){
OtherClass::otherMethod();
}
public function myMethod(){
echo 'Tada!';
}
}
class OtherClass{
public function otherMethod(){
echo get_class($this);
$this->myMethod();
}
}
$thing = new MyClass();
$thing->callOtherMethod();
This somehow worked without issue until I did some cleanup and explicitly declared the OtherClass' methods static as they were meant to be. Everything worked because, for some reason I was unaware of, $this while used within OtherClass instead references the instantiated object that called it (i.e. MyClass).
I didn't think this should be possible, should it? I know it's bad coding standards and I'm making revisions to avoid it, but I found it really, really weird.
I'm revising my OOPs concepts in PHP. I have a simple php code here for practising visibility.
When i declare $name as private in Big_Animal,
1)Why it doesn't throw an error when i try to assign a different value for $name from outside the class (ie. $lion->name="King")?
2)Why it doesn't throw an error when i try to reassign $name in Lion class (ie. $this->name="John").
I'm confused coz as per my knowledge, private properties can only be accessed within the class that defines the property.
The other thing i'm not clear about is protected properties. As per my understanding, protected properties can be accessed only within the class itself and its child classes. Can it be accessed by its grandchild classes?
Thank you.
<?php
abstract class Big_Animal{
private $name="Mary";
abstract public function Greet();
public function Describe(){
return "name: ".$this->name;
}
public function __set($name,$value){
$this->name=$value;
}
public function __get($name){
return $this->name;
}
}
class Lion extends Big_Animal{
public function Greet(){
$this->name="John"; //no error for this
return " roar!";
}
public function Describe(){
return parent::Describe()." I'm a Lion!";
}
}
$lion = new Lion();
$lion->name="King"; //no error for this
echo $lion->Describe();
echo $lion->Greet();
?>
Your magic method accessors (__set and __get) are public in the base, abstract class. They are the ones writing to the private data when you access the property directly. Try commenting out the magic methods and see. Then, the output is "name: Mary I'm a Lion! roar!".
Add this as the first statement in Lion::Describe():
echo "Lion's name: " . $this->name . "\n";
As you can see, the output is now: "Lion's name: King". Both $this->name="John"; and $lion->name="King"; are modifying the public property on Lion class' object. It's unfortunate that you can have both public and private properties of the same name, but you can. They are simply different variables (in different scopes).
Protected properties can be accessed from grandchildren. Most of your properties should be protected, unless you have a really strong reason to protect it (therefore using private). Public properties aren't used much in larger projects (depending on your style). I'd prefer to stick with explicit accessors. As a project progresses and becomes more complex, you'll be glad you chose to use accessors for each variable. I prefer to use a generator that will generate the scaffolding accessors for you. It saves a lot of time, cuts down on errors, and makes the creation of accessors a lot cheaper (and therefore more common).
UPDATE (a response to the comment below):
1) and 2) You're not getting errors because you're editing the Public variable in both of the instances that I listed in my 2) above. Try var_dump($lion):
object(Lion)#1 (2) {
["name":"Big_Animal":private]=>
string(4) "Mary"
["name"]=>
string(4) "John"
}
Also, if you explicitly add a private or protected member variable to the Lion class, you will get the error that you expect. I would agree with you that that's not very intuitive, but appears to be the current reality in PHP.
3) http://www.ibm.com/developerworks/opensource/library/os-php-7oohabits/ has an example of writing public accessors for private member variables (although, again, I'd recommend writing public accessors for protected member variables instead).
Because you are using magic method of __set()
__set() is run when writing data to inaccessible properties.
It is also possible to get the value by $lion->name because you also use __get().
To elaborate on my comment... You are using a function called __set, what this does is that every time you try to set a value on an unknown property on this class, this specific function is called.
In your function, you are always changing the private field name, into the value provided. Since this class has access to it's field, this is set.
Even if you wrote $lion->foo = "bar", the name would be set to bar, due to your function __set
I think the answer for your question is here
Abstract methods cannot be private, because by definition they must be
implemented by a derived class. If you don't want it to be public, it
needs to be protected, which means that it can be seen by derived
classes, but nobody else.
Matt Zandstra gives the following example in his text "PHP Objects Patterns and Practice" to illustrate the __get() method:
class Person {
function __get( $property ) {
$method = "get{$property}";
if ( method_exists( $this, $method ) ) {
return $this->$method();
}
}
function getName() {
return "Bob";
}
function getAge() {
return 44;
}
}
In reality, we know we would never actually create such methods (getName and getAge) to return such static values, but instead - we would create name and age properties in the object and return those using the $this operator.
My question is whether this example actually shows utility. And if it does not, could somebody provide a better example of why one would use __get() for the same sort of purpose?
Justification for asking
If we were to use name and age properties in the object, then the __get() function would not be fired anyway, because attempting to get these properties with:
$person = new Person();
$name = $person->name;
would cause either the name property to actually be returned if it were public, or cause a visibility error if it were private or protected. The __get() function would not be executed in either of these 'real' cases... am i missing something?
I'm fully aware that the above code works.
I am not convinced that it is a practical example.
You are absolutely right - I am impressed that you are quoting from a book, that example just plain sucks.
Using the magic __get method to call methods is just wrong, there are other magic methods just for that kind of usage:
__call()
__callStatic()
__invoke()
__get() and __set() should be used to read and write non declared object properties.
The actual functionality of magical methods is totally up to the developer to handle in any way they see fit. The difference is in how they are invoked.
$obj->property; // invokes __get(), if defined
$obj->method(); // invokes __call(), if defined
$obj(); // invokes __invoke() if defined (php 5.3+)
etc. So if you want to have __get() call a method internally, you can. How you want to handle it depends entirely on how you want to design your application.
About __get(), if you have a public member and try to call it with ->, the __get() will not fire. However, if you try to access a non-accessible member (either protected, private, or nonexistent) __get() will fire and you can handle it how you like.
It is my understanding that the main purpose of __get() at least according to php is to eliminate the need to write getters for every member. Compare with __set() for setters. I don't want to get into this here, but I think the use of getters/setters should raise some red flags about design. However, __get()'s intended purpose does not have to be adhered to except for the standards of those developing the application.
Two examples of how __get() might be used are to initialize a property that may not be needed upon instantiation (e.g. by a DB query) thus reducing overhead. Another may be if you have properties stored in an array, magical get may return the value mapped to the key of the requested property.
With the php magic functions, you can do some very cool things and you can write code that is more extensible by using these special invocations. Something I like to do:
class application {
public function __call($_, $_) {
throw new Exception("PUT and DELETE not supported");
}
public function POST() {
//update data
header("Location: $_SERVER[PHP_SELF]", true, 303);
}
public function GET() {
//display data
}
public static function inst() {
return new self;
}
}
application::inst()->$_SERVER['REQUEST_METHOD']();
Of course, this is using __call() rather than __get(), but the principle's the same. In this case it's just a sanity check.
As php.net states
"__get() is utilized for reading data
from inaccessible properties."
This means that __get() (if it's defined) is called whenever you try to access a property that does not exist or is private / protected. The above example shows a way for getting the values of those private properties by calling their accessors (getters) whenever someone tries to get the values.
For example, calling
echo $a -> publicPropery or echo $a -> getPublicProperty()
would result in the same thing. However if you call $a -> privateProperty you would get an error, and
$a -> getPrivateProperty()
would be OK.
But, if you defined __get() whenever you call $a -> privateProperty, __get() is executed and redirected to $a -> getPrivateProperty(). In this case you would always succeed in getting the value and still keeping security in mind. Even more, since you check for the existance of the property getter in __get() you could show an appropriate error or throw an exception if someone tries to access unexisting properties, which will override php's visibility errors.
<?php
class data {
public $name="Ankur DalsaniYa"; \\ I wont to change name
public function __get($var) {
print "Attempted to retrieve '<b>$var</b>' and failed...\n";
//$var is print the Unknown and Not Define but call variable print
}
}
$data = new data;
echo "<br> Not Define Variable Call : ";
print $data->title; // Not Defined variable Call then call __get function
echo "<br><br> Define Variable Call : ";
print $data->name; // Define variable Call then Not call __get function
?>
First of all: A quite similar problem has been posted and somehow solved already, but is still not answering my specific problem. More about this later.
In words: I have a base class which provides some methods to all childs, but doesn't contain any property. My child is inheriting these methods, which should be used to access the child's properties.
If the child's property is protected or public, all works fine, but if the child's property is private, it fails without error (just nothing happens).
In code:
class MyBaseClass {
public function __set($name, $value) {
if(!property_exists($this, $name))
throw new Exception("Property '$name' does not exist!");
$this->$name = $value;
}
}
class ChildClass extends MyBaseClass {
public $publicProperty;
protected $protectedProperty;
private $privateProperty;
}
$myChild = new ChildClass();
$myChild->publicProperty = 'hello world'; //works of course!
$myChild->protectedProperty = 'hello world'; //works as expected
$myChild->privateProperty = 'hello world'; //doesn't work?
The above mentioned similar problem got the solution to use the magic __set() method to access the private properties, but this I am already doing. If I implement __set() within the child, it works of course, but the idea is, that the child inherits the __set() from it's parent, but obviously it can't access the child's private method.
Is that on purpose? Am I doinf something wrong? or is my approach just crap by design?
Background:
My original idea was: The whole dynamic thing about __set() is something I don't like. Usually a private property should never be accessible from outside, so I implemented throwing __set- and __get-methods in my ultimate base class (from which all classes inherit).
Now I want to dynamicially spawn an instance from an XML file and therefore need access to properties. I made the rule, that any XML-instantiatable class needs to implement the magic __set() method and so can be created dynamicially. Instead of implementing it in every Class that might be spawned some day, I decided to make them inherit from a class called like class Spawnable { } which provides the needed __set-method.
This is the difference between private and protected. Private methods and properties cannot be inherited or reached. You will need to change them to protected instead.
See the manual on visibility
Members declared protected can be
accessed only within the class itself
and by inherited and parent classes.
Members declared as private may only
be accessed by the class that defines
the member.
I guess you could fashion something using Reflection. For example, in your Spawnable class:
public function __set($name, $value)
{
$reflector = new ReflectionClass(get_class($this));
$prop = $reflector->getProperty($name);
$prop->setAccessible(true);
$prop->setValue($this, $value);
}
Not the prettiest of code, though.
After reviewing my concept, I think it's a bad idea, to go with that approach. This is a general issue with PHP's lack of differing between properties and fields. Of course private fields should never be accessible from outside, but only properties, which are defined by the programmer. The absence of auto-properties (and I don't mean these magical methods __set() and __get()) or some conventional rules for property access, makes it difficult to guess, which naming convention has been used by the programmer when implementing setters for private fields in his class.
The better concept here might be, to rely on the existence of well-named setters for each spawnable class, although it might break, if someone contributed code, which is not implementing the expected conventional named setters.
However, many thanks for your thoughts and hints!
I'm going to try something with the format of this question and I'm very open to suggestions about a better way to handle it.
I didn't want to just dump a bunch of code in the question so I've posted the code for the class on refactormycode.
base class for easy class property handling
My thought was that people can either post code snippets here or make changes on refactormycode and post links back to their refactorings. I'll make upvotes and accept an answer (assuming there's a clear "winner") based on that.
At any rate, on to the class itself:
I see a lot of debate about getter/setter class methods and is it better to just access simple property variables directly or should every class have explicit get/set methods defined, blah blah blah. I like the idea of having explicit methods in case you have to add more logic later. Then you don't have to modify any code that uses the class. However I hate having a million functions that look like this:
public function getFirstName()
{
return $this->firstName;
}
public function setFirstName($firstName)
{
return $this->firstName;
}
Now I'm sure I'm not the first person to do this (I'm hoping that there's a better way of doing it that someone can suggest to me).
Basically, the PropertyHandler class has a __call magic method. Any methods that come through __call that start with "get" or "set" are then routed to functions that set or retrieve values into an associative array. The key into the array is the name of the calling method after getting or setting. So, if the method coming into __call is "getFirstName", the array key is "FirstName".
I liked using __call because it will automatically take care of the case where the subclass already has a "getFirstName" method defined. My impression (and I may be wrong) is that the __get & __set magic methods don't do that.
So here's an example of how it would work:
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
}
$props = new PropTest();
$props->setFirstName("Mark");
echo $props->getFirstName();
Notice that PropTest doesn't actually have "setFirstName" or "getFirstName" methods and neither does PropertyHandler. All that's doing is manipulating array values.
The other case would be where your subclass is already extending something else. Since you can't have true multiple inheritances in PHP, you can make your subclass have a PropertyHandler instance as a private variable. You have to add one more function but then things behave in exactly the same way.
class PropTest2
{
private $props;
public function __construct()
{
$this->props = new PropertyHandler();
}
public function __call($method, $arguments)
{
return $this->props->__call($method, $arguments);
}
}
$props2 = new PropTest2();
$props2->setFirstName('Mark');
echo $props2->getFirstName();
Notice how the subclass has a __call method that just passes everything along to the PropertyHandler __call method.
Another good argument against handling getters and setters this way is that it makes it really hard to document.
In fact, it's basically impossible to use any sort of document generation tool since the explicit methods to be don't documented don't exist.
I've pretty much abandoned this approach for now. It was an interesting learning exercise but I think it sacrifices too much clarity.
The way I do it is the following:
class test {
protected $x='';
protected $y='';
function set_y ($y) {
print "specific function set_y\n";
$this->y = $y;
}
function __call($function , $args) {
print "generic function $function\n";
list ($name , $var ) = split ('_' , $function );
if ($name == 'get' && isset($this->$var)) {
return $this->$var;
}
if ($name == 'set' && isset($this->$var)) {
$this->$var= $args[0];
return;
}
trigger_error ("Fatal error: Call to undefined method test::$function()");
}
}
$p = new test();
$p->set_x(20);
$p->set_y(30);
print $p->get_x();
print $p->get_y();
$p->set_z(40);
Which will output (line breaks added for clarity)
generic function set_x
specific function set_y
generic function get_x
20
generic function get_y
30
generic function set_z
Notice: Fatal error: Call to undefined method set_z() in [...] on line 16
#Brian
My problem with this is that adding "more logic later" requires that you add blanket logic that applies to all properties accessed with the getter/setter or that you use if or switch statements to evaluate which property you're accessing so that you can apply specific logic.
That's not quite true. Take my first example:
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
}
$props = new PropTest();
$props->setFirstName("Mark");
echo $props->getFirstName();
Let's say that I need to add some logic for validating FirstNames. All I have to do is add a setFirstName method to my subclass and that method is automatically used instead.
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
public function setFirstName($name)
{
if($name == 'Mark')
{
echo "I love you, Mark!";
}
}
}
I'm just not satisfied with the limitations that PHP has when it comes to implicit accessor methods.
I agree completely. I like the Python way of handling this (my implementation is just a clumsy rip-off of it).
Yes that's right the variables have to be manually declared but i find that better since I fear a typo in the setter
$props2->setFristName('Mark');
will auto-generate a new property (FristName instead of FirstName) which will make debugging harder.
I like having methods instead of just using public fields, as well, but my problem with PHP's default implementation (using __get() and __set()) or your custom implementation is that you aren't establishing getters and setters on a per-property basis. My problem with this is that adding "more logic later" requires that you add blanket logic that applies to all properties accessed with the getter/setter or that you use if or switch statements to evaluate which property you're accessing so that you can apply specific logic.
I like your solution, and I applaud you for it--I'm just not satisfied with the limitations that PHP has when it comes to implicit accessor methods.
#Mark
But even your method requires a fresh declaration of the method, and it somewhat takes away the advantage of putting it in a method so that you can add more logic, because to add more logic requires the old-fashioned declaration of the method, anyway. In its default state (which is where it is impressive in what it detects/does), your technique is offering no advantage (in PHP) over public fields. You're restricting access to the field but giving carte blanche through accessor methods that don't have any restrictions of their own. I'm not aware that unchecked explicit accessors offer any advantage over public fields in any language, but people can and should feel free to correct me if I'm wrong.
I've always handled this issue in a similar with a __call which ends up pretty much as boiler plate code in many of my classes. However, it's compact, and uses the reflection classes to only add getters / setters for properties you have already set (won't add new ones). Simply adding the getter / setter explicitly will add more complex functionality. It expects to be
Code looks like this:
/**
* Handles default set and get calls
*/
public function __call($method, $params) {
//did you call get or set
if ( preg_match( "|^[gs]et([A-Z][\w]+)|", $method, $matches ) ) {
//which var?
$var = strtolower($matches[1]);
$r = new ReflectionClass($this);
$properties = $r->getdefaultProperties();
//if it exists
if ( array_key_exists($var,$properties) ) {
//set
if ( 's' == $method[0] ) {
$this->$var = $params[0];
}
//get
elseif ( 'g' == $method[0] ) {
return $this->$var;
}
}
}
}
Adding this to a class where you have declared default properties like:
class MyClass {
public $myvar = null;
}
$test = new MyClass;
$test->setMyvar = "arapaho";
echo $test->getMyvar; //echos arapaho
The reflection class may add something of use to what you were proposing. Neat solution #Mark.
Just recently, I also thought about handling getters and setters the way you suggested (the second approach was my favorite, i.e. the private $props array), but I discarded it for it wouldn't have worked out in my app.
I am working on a rather large SoapServer-based application and the soap interface of PHP 5 injects the values that are transmitted via soap directly into the associated class, without bothering about existing or non-existing properties in the class.
I can't help putting in my 2 cents...
I have taken to using __get and __set in this manor http://gist.github.com/351387 (similar to the way that doctrine does it), then only ever accessing the properties via the $obj->var in an outside of the class. That way you can override functionality as needed instead of making a huge __get or __set function, or overriding __get and __set in the child classes.