SitePoint Sponsor |
|
User Tag List
Results 126 to 150 of 325
-
Sep 14, 2005, 11:47 #126
- Join Date
- Aug 2003
- Location
- Toronto
- Posts
- 300
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by arborint
PHP Code:interface PropertyAccessors extends Properties {
public function get($name);
public function set($name, $value);
public function propertytIsset($name); // ? name
public function propertyUnset($name); // ? name
}
-
Sep 14, 2005, 11:47 #127
- Join Date
- May 2005
- Location
- Finland
- Posts
- 608
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by arborint
-
Sep 14, 2005, 12:21 #128
not to randomly make comments, but $name is pretty bland, generic, $property is more specific. and $propertyName is even more specific, because that is what is being passed in the signature ((string) $propertyName, (mixed) $value). but $property makes alot of sense because of the way it might be used within the method, by returning the actual property of the class.
i know this sounds picky, and i don't mean to sound rude, but i mean to encourage code that is more readable, because if you start now with the basic things in being generic, those practices will be used elsewhere, where they might not be as readable or easy to follow. someone could easily change it to where they are using $name to call a specific accessor method of a class or just even a method, unless you want specifically want to leave it generic so that someone could do the following.
PHP Code:// implements Properties
public function __get($name) {
// hacked way of getting accessor
$name = 'get_'.$name;
return ($this->$name());
}
public function isFoo() { return false; }
public function __get($name) { return $this->$name();}
PHP Code:public function __get($property) { return ($this->$property); }
the php manual is a great thing, but it too could use some improvements. obviously if the status quo was good enough, so many people would not be interested in this thread.
-
Sep 14, 2005, 12:39 #129
- Join Date
- Mar 2005
- Posts
- 53
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Gah - I go to sleep, and this is what I get...28 new posts
.
You may be able to emulate uniqueness of key, but you cannot emulate depth and hierarchy that way. What if I want to get back an array of all my levels?
@get/set/__get/__set discussion:
Does all this seem a bit nit-picky, with everyone interjecting their particular opinions regarding a naming scheme? Let's pick the clearest interface name (Property?) and add basic/commonly used property methods (set/get, facaded by __set/__get). Thoughts?
Regards,
Tyler Tompkins
-
Sep 14, 2005, 12:49 #130
- Join Date
- Oct 2004
- Location
- Kansas City, MO
- Posts
- 68
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by mx2k
To address the specific concern, I understand what you mean, but I would argue that $property is implied, thus $name == $propertyName. I personally favor the $key use as it makes sense in the case of arrays (array == $key => $value is probably a maxim somewhere), but I adopted (arbitrarily and am open to change) $name to keep continuity with the manual.
i know this sounds picky, and i don't mean to sound rude, but i mean to encourage code that is more readable, because if you start now with the basic things in being generic, those practices will be used elsewhere, where they might not be as readable or easy to follow.
.. snip ..
so being more specific allows the code to be self documenting, which will make less work later for documenting the api and it gives a better idea of what the class and the way it was intended to be used.
And without any further talk... here's the last proposed code (available at revision 4 in the subversion repository:
PHP Code:<?php
/**
* Provides an interface for storing and retrieving any number of "properties"
* via PHP's {@link http://us2.php.net/manual/en/language.oop5.magic.php magic
* methods}.
*
* @license http://www.gnu.org/copyleft/lesser.html LGPL
* @author Collectively authored via
* {@link http://www.sitepoint.com/forums/showthread.php?t=298611}.
*/
interface Properties
{
/**
* Retrieves a mixed value from this container by its given <i>$name</i>.
*
* Should throw {@link PropertyNotFoundException} if the equivilent of
* <i>__isset($name) == FALSE</i> is found.
*
* @param string
* @return mixed
*/
public function __get($name);
/**
* Sets the property of a given <i>$name</i> to a given <i>$value</i>.
*
* @param string
* @param mixed
*/
public function __set($name, $value);
/**
* Returns <i>TRUE</i> if a given property is set, <i>FALSE</i> otherwise.
*
* @param string
* @return boolean
*/
public function __isset($name);
/**
* Unsets a property based on the provided <i>$name</i>.
*
* Should perform no action if {@link __isset($name)} returns false.
*
* @param string
*/
public function __unset($name);
}
if (!class_exists('RuntimeException')) {
// To be included until first stable release of PHP 5.1
class RuntimeException extends Exception { }
}
/**
* Should be thrown by {@link Properties::__get()} when an attempt to access an
* unknown property name is made.
*/
class PropertyNotFoundException extends RuntimeException { }
-
Sep 14, 2005, 12:55 #131
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Nothing wrong with that. I can live with that, and without losing any sleep
-
Sep 14, 2005, 13:31 #132
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
PHP Code:public function __set($name, $value);
-
Sep 14, 2005, 13:49 #133
- Join Date
- Oct 2004
- Location
- Kansas City, MO
- Posts
- 68
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by kyberfabrikken
Of course, then we get into trying to guess how Properties might be applied. The next step is BlackHoleProperties where you can __set(), but not __get(). Calling __get() on something that doesn't exist is bound to happen and we need to know how to handle it - return null, thrown an exception, die, etc. - but being read-only should be left to the developer.
Along these lines - should __unset() throw an exception similar to __get()? Basically, all retrievals should return __isset() == true or a PropertyNotFoundException is thrown.
-
Sep 14, 2005, 14:35 #134
- Join Date
- Aug 2003
- Location
- Toronto
- Posts
- 300
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Travis S
-
Sep 14, 2005, 14:53 #135I personally favor the $key use as it makes sense in the case of arrays
If you want to implement Properties and create your own custom accessor methods, then you're more than welcome to. The only thing to keep in mind is that you're attempting to make something that can be interchanged with other parts. If you move away from relying on __get('value') or it's object->value usage, you've stepped away from the standard and moved to relying on the implementation of the object.
but most people never look to know this or find it out. so if we design a class implimenting interface properties, and then inherit from that class. Then average joe who is utilizing this with an ide, sits and sees that this class inherits a method __get($name) and then goes creates a hack here and there.
but enough on that, i'm tired, moody and i digress.
-
Sep 14, 2005, 14:59 #136
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by jayboots
Another is how to handle these rarer uses. Do we bother everyone with an exception when the spirit of PHP is perhaps looser than that, or do we say that in those cases implement things like isWritable($name) and isReadable($name) as standard extensions. If you can always do an "if ($data->isWritable($name)) {" then fine, but if the error by its nature needs to be handled farther away then an exception. I don't know if anyone is in PHP rushing down the "execption for everything" path.Christopher
-
Sep 14, 2005, 17:04 #137
- Join Date
- Apr 2003
- Location
- London
- Posts
- 2,423
- Mentioned
- 2 Post(s)
- Tagged
- 0 Thread(s)
Hi...
Originally Posted by Travis S
yours, MarcusMarcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things
-
Sep 14, 2005, 17:08 #138
I would like to make a couple of suggestion:
- These interfaces should ideally be implementable in php4, and should therefore support both the magic methods and get()/set(); additionally, I would vote for calling the other methods isset() and unset() for the sake of succinctness.
- Properties that are null should return isset() = false, as I believe this follows php's semantics for variables?
- Directly accessing properties is a bad idea (although I'm not sure if anyone suggested this) because we may want to lazy load objects.
- Possibly beyond the scope of this discussion, but... say this interface is being used as part of an ORM implemententation, and we want certain properties to return a collection of values; how would this be implemented? In my personal code, I use Collection objects that implement a simple iterator interface. How do you guys feel about this?
Keep up the good work, I feel a concensus coming on
-
Sep 14, 2005, 17:22 #139
- Join Date
- Apr 2003
- Location
- London
- Posts
- 2,423
- Mentioned
- 2 Post(s)
- Tagged
- 0 Thread(s)
Hi.
A major, really the major, decision seems to be slipping under the radar again. Whether properties are going to be accessed as either of...
PHP Code:$value = $container->key;
$value = $container[$key];
$value = $container->get('key');
$value = $container->getKey()
I am not against this choice, but I cannot believe it hasn't been debated. Here are some shortcomings:
1) Reflection is knackered.
2) Mistakes will add variables: $container->unknown_key = 'something'.
3) It's difficult to decorate/proxy.
4) It makes use of __get() and there is only one of these. That's one less card for the developer to play later.
5) It can nameclash with existing variables in the object.
Also things are getting complicated again for no good reason. Who says there has to be an unset() method? That may be really hard to implement or incorrect, say for a database row. An implementer may choose to add it, but as you don't need it in every case, it shouldn't be in the interface.
See how abstractions bloat? Insidious things aren't they. Think of the SPL rewind() for an example of a painful affliction. This is armchair generalship. We need to look at the code that's out there.
yours, MarcusMarcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things
-
Sep 14, 2005, 18:06 #140
- Join Date
- Aug 2003
- Location
- Toronto
- Posts
- 300
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by lastcraft
Originally Posted by lastcraft
Originally Posted by lastcraft
Originally Posted by lastcraft
Originally Posted by lastcraft
Originally Posted by lastcraft
Originally Posted by lastcraft
All this perhaps suggests that there should possibly be an interface for directing the dynamic mechanisms. I think it also turns the discussion back to that of concrete vs dynamic, perhaps because some seem to care about PHP4 compatability. It could very well be that there is no happy common ground between the concrete and dynamic camps. The features for dynamic mechanisms aren't really capable enough until 5.1 and IMO, if you are going dynamic it is probably because you want to avoid using some of the heavier Javaesque idioms that concrete classes in PHP tend to elicit.
Best Regards.
-
Sep 14, 2005, 18:12 #141
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
An implementer may choose to add it, but as you don't need it in every case, it shouldn't be in the interface.
That is one way to be sure it is implemented, whilst keeping the Interface slim.
-
Sep 14, 2005, 19:16 #142
- Join Date
- Apr 2003
- Location
- London
- Posts
- 2,423
- Mentioned
- 2 Post(s)
- Tagged
- 0 Thread(s)
Hi...
Originally Posted by jayboots
Originally Posted by jayboots
Originally Posted by jayboots
Originally Posted by jayboots
Originally Posted by jayboots
Originally Posted by jayboots
It comes down to what we mean by the interface. If you think of it as a blank slate to add and remove slots at will, then you will want unset(). If you view it as a fixed set of slots (DB row or config file) then using an unknown field will throw an exception and unset() is an anathema.
I think this highlights an important difference between something called Properties and something called Hash. I think an interface called Keyed (still my favourite) could apply to both.
Originally Posted by jayboots
Originally Posted by jayboots
yours, MarcusMarcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things
-
Sep 14, 2005, 19:22 #143
- Join Date
- Jun 2003
- Location
- Iowa, USA
- Posts
- 3,749
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by lastcraft
Jason Sweat ZCE - jsweat_php@yahoo.com
Book: PHP Patterns
Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
Detestable (adjective): software that isn't testable.
-
Sep 14, 2005, 19:27 #144
- Join Date
- Nov 2003
- Location
- Huntsville AL
- Posts
- 706
- Mentioned
- 4 Post(s)
- Tagged
- 1 Thread(s)
Just thought I would throw in a concrete implementation of Properties. It's a modified version of the Request object from the skeleton thread.
PHP Code:<?php
require_once 'Properties.interface.php';
/* ------------------------------------------
* Taken from the Skelton framework
* Basically decides between $_GET and $_POST
* And cleans up slashes etc
*
*/
class ZRequest implements Properties
{
protected $props = array();
protected $post = FALSE;
function __construct()
{
/* Store any command line arguments */
if (isset( $_SERVER['argv'][1])) {
parse_str($_SERVER['argv'][1],$_GET);
}
/* Decide between post or get */
if (!strcasecmp($_SERVER['REQUEST_METHOD'], 'POST')) {
$this->props = $_POST;
$this->post = TRUE;
}
else $this->props = $_GET;
/* Nice to know the script */
$this->props['PHP_SELF'] = $_SERVER['PHP_SELF'];
/* Clean up silly quotes */
if (get_magic_quotes_gpc()) {
$this->removeSlashes($this->props);
}
}
function removeSlashes(&$str)
{
if (is_array($str)) {
foreach ($str as $key => $val) {
if (is_array($val)) $this->removeSlashes($val);
else $str[$key] = stripslashes($val);
}
}
else $str = stripslashes($str);
}
function __isset($name)
{
return isset($this->props[$name]);
}
function __unset($name)
{
throw new PropertyReadOnlyException("Request $name");
}
function __set($name,$value)
{
throw new PropertyReadOnlyException("Request $name");
}
function __get($name)
{
if (!isset($this->props[$name])) {
throw new PropertyNotFoundException("Request $name");
}
return $this->props[$name];
}
function is_set($name) { return isset($this->props[$name]); }
function get($name) { return $this->$name; }
function isPost() { return $this->post; }
}
?>
Note 2: I made the props read only on the theory that one should not update posted variables.
Note 3: I snuck in a get() method so I didn't have to change some of my other code. But $request->key works fine.
Note 4: Might try to specify the format of the Exception message strings.
-
Sep 14, 2005, 21:07 #145
- Join Date
- Nov 2002
- Posts
- 841
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Marcus, I agree there should be more debate. __get/__set does have consequences and gotchas.
For example, Here is another implementation to look at
PHP Code:<?php
interface Properties {
public function __get($property);
public function __set($property, $value);
public function __isset($property);
public function __unset($property);
}
class AccessorPropertySupport implements Properties {
public function __get($property) {
if (method_exists($this, 'get' . $property)) {
$method = 'get' . $property;
return $this->$method();
} else {
$internalProperty = '_' . $property;
return $this->$internalProperty;
}
}
public function __set($property, $value) {
if (method_exists($this, 'set' . $property)) {
$method = 'set' . $property;
$this->$method($value);
} else {
$internalProperty = '_' . $property;
$this->$internalProperty = $value;
}
}
public function __isset($property) {
if (method_exists($this, 'get' . $property)) {
return TRUE;
} else {
$internalProperty = '_' . $property;
return isset($this->$internalProperty);
}
}
public function __unset($property) {
throw new Exception('Cannot remove properties.');
}
}
class Rectangle extends AccessorPropertySupport {
protected $_width;
protected $_length;
function __construct($width, $length) {
$this->width = $width;
$this->length = $length;
}
function getArea() {
return $this->_width * $this->_length;
// We cannot use the same notation from within the class as
// we do externally to the class because our magic method
// does not get called internally.
// return $this->width * $this->length
// does not work here.
}
}
$rec =& new Rectangle(10, 20);
echo 'width:', $rec->width, "<BR>\n";
echo 'length:', $rec->length, "<BR>\n";
echo 'area:', $rec->area, "<BR>\n";
?>
-
Sep 14, 2005, 21:33 #146
- Join Date
- Oct 2004
- Location
- Kansas City, MO
- Posts
- 68
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by lastcraft
Seriously though, I don't see a problem with them being there. If your loading a read-only Properties, throw an exception when a set or unset is attempted. Otherwise, there's two interfaces - the read-only - __get() & __isset() - and the mutable - add __set() & __unset(). Beyond that, it's up to the implementor to say when a given action is allowed. Anyhow, I think the bigger issue is introspection.
Should a Properties/Keyed implementation provide getKeys() which returns an array of key names that are available? In a dynamic setting, this would return basically an array_keys($this->_corral), while a read-only might return the meta-data from the db table that was used to create the object.
Originally Posted by ahundiak
Originally Posted by ahundiak
-
Sep 14, 2005, 21:37 #147
- Join Date
- Aug 2003
- Location
- Toronto
- Posts
- 300
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Good points, lastcraft. I'll try once again but it is certainly getting harder.
Originally Posted by lastcraft
Originally Posted by lastcraft
Originally Posted by lastcraft
Originally Posted by lastcraft
That said, I think I should have rather said that the default behaviour should be to trigger errors -- that's actually what I do in my classes for all default magic behaviour.
Originally Posted by Dr Livingston
Best regards.
-
Sep 14, 2005, 21:42 #148
- Join Date
- Sep 2003
- Location
- Wixom, Michigan
- Posts
- 591
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by lastcraft
PHP Code:class LoggerDecorator() {
function __construct($decorated){
$this->decorated = $decorated;
}
function set($name, $value){
Logger::log("setting $name to $value");
return $this->decorated->set($name, $value);
}
function _call($methodName, $parameters){
$this->decorated->$methodName($parameters);
}
}
Garcia
-
Sep 14, 2005, 21:44 #149
- Join Date
- Oct 2004
- Location
- Kansas City, MO
- Posts
- 68
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Selkirk
PHP Code:return $this->__get('width') * $this->__get('length');
// or
return $this->get('width') * $this->get('length');
// or your internal storage
return $this->_width * $this->_length;
// or mine internal storage
return $this->_corral['width'] * $this->_corral['length'];
PHP Code:interface Keyed {
public function get($key);
public function has($key);
}
interface MagicKeyed extends Keyed {
public function __get($key); // maps to get($key) or vice-versa
public function __isset($key); // maps to has($key) or vice-versa
}
PHP Code:// will work
$keyed->someArray[1]->value->key;
// will not work without some fancy implementation
$keyed->get('someArray[1]')->get('value')->get('key');
-
Sep 14, 2005, 22:48 #150
- Join Date
- Aug 2003
- Location
- Toronto
- Posts
- 300
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
@Selkirk: I don't like that __get can't seem to chain (you can call $rec->getArea() and get expected results even if getArea() uses the public property access) but why wouldn't an accessor method reference internals? After all, aren't accessors supposed to expose internal storage? For example, if I implemented getLength() in your example class, it would clearly be wrong for it to access $this->length -- that is what it is supposed to be providing.
Bookmarks