Hello there...
I am making my debut appearance here hoping that I am not giving offense
to anyones well honed php-instincts or programming practices with my
feature-request. This is what it comes down to, I guess. A Feature
Request for some meta-info on the instantiated PHP-Objects. Specifically
I want to know how many references are currently pointing to any one
object. Since PHP's Memory Management is based on Reference-Counting
this information should already be available "somewhere". Not knowing
any php-source-code internals, I can't even guess at the problems which
prohibit the implementation of such a feature. Nevertheless I'd like to
point out an advantage to the community if the reference-count were
available.
I have been working on a large project for 6 years now and I got to a
point where I'd like to cache certain objects singleton-like. To better
explain my problem I provide this small example which surely is
error-prone but should get the basic idea across.
<?
class MyObject {
private static $instances = array();
protected $id;
private function __constructor($id){
$this->id = $id;
}
/**
* Returns an instance of the class.
* If no object was instantiated with the given $id before,
* it will instantiate a new object which will be associated
with the given $id.
*
* It will also check the current memory-usage and if its used
up for more than
* 80% it will call the collect() method.
*
* @param int $id
* @return MyObject
*/
public static function getInstance($id){
if ( !isset(self::$instances[$id]) ) {
//check the used up memory wether to collect unused
objects or not
if ( memory_get_usage()
> ini_get('memory limit')*0.8 )
self::collect();
self::$instances[$id] = new MyObject($id);
}
return self::$instances[$id];
}
/**
* Removes any object from the cache-list which is not
referenced anymore.
* (safe for the list and the local-reference to it)
*/
public static function collect(){
foreach( self::$instances as $id => $instance ) {
if ( reference_count($instance) < 3 )
unset(self::$instances[$id]);
}
}
}
?>
As you can see I boldly used the function reference_count(Object) even
though it doesn't exist. This is exactly what I'd need to allow my
concept to work. I keep thinking of any other solutions, but up until
now, I didn't find any better solution for this problem. Of course I can
always ignore the memory usage and hope that it wont hit the limit...but
hoping is a rather ethereal and mystic idea which doesn't go well with
my preferred down-to-earth 1 plus 1 equals 2 programming.
I know that a lot of you may say: Why do need to do that?...and I'd have
to think for 3 days and then write for 4 days and would give up. It
seems like a nice solution to me and if any of you have an idea as to
how I could implement this differently, please feel free to point it out
to me.
Thanks for reading this far.
Lars
Hi!
Lars Schultz wrote:
As you can see I boldly used the function reference_count(Object) even
though it doesn't exist. This is exactly what I'd need to allow my
concept to work.
Some time ago I created a patch to implement a ref_count() function
which works the way you suggested. But I'm not sure if it's
OK/complete... and I'm not sure if something like that is really needed
in the core (and I'm definetly not the person to decide on that ;-)).
Anyway, I attatched a simple patch against current 5_2 branch to this
mail, perhaps it helps.
Best regards
Andreas
Some time ago I created a patch to implement a ref_count() function
which works the way you suggested. But I'm not sure if it's
OK/complete... and I'm not sure if something like that is really needed
in the core (and I'm definetly not the person to decide on that ;-)).
If you talk about objects, your patch exposes wrong refcount. Your patch
exposes zval refcount, however there can be a number of zvals referring
to the same object, and the actual object storage keeps its own
refcount, see zend_objects_API.c (provided your object is a standard
Zend object).
Actually, since each of these zvals can hold own refcount and we can not
know what variables refer to the given object, I do not see how one
could really calculate the number of different places that the object is
referred to, unless you know your application really well so you could
know how many places refer to the object and what exactly they are.
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Andreas Korthaus wrote:
Some time ago I created a patch to implement a ref_count() function
which works the way you suggested. But I'm not sure if it's
OK/complete... and I'm not sure if something like that is really
needed in the core (and I'm definetly not the person to decide on that
;-)).
Wow! This is great news...though I have no idea what to do with the
patch and how to apply it to the php-source-code. The trouble is that I
have to use the default php-engine because it should be runnable on any
host...with some extensions. I don't guess it'd be possible to pack the
functionality into en extension which could then be loaded more easily
into the engine?
Anyway, I attatched a simple patch against current 5_2 branch to this
mail, perhaps it helps.
Thanks anyway! It was an interesting read though my c and c++ knowledge
is far from complete so i don't understand the workings, really...Maybe,
if I feel restless, I'll have a look at the sources, though I wouldn't
know where to start.
As you can see I boldly used the function reference_count(Object) even
though it doesn't exist. This is exactly what I'd need to allow my
concept to work. I keep thinking of any other solutions, but up until
now, I didn't find any better solution for this problem. Of course I can
Note that the engine does not guarantee you any particular value of the
refcount. Passing parameters around, accessing variables, etc. may
change the refcount. One thing the engine guarantees you is that once no
links to the variable exist it would be destroyed (which may not happen
immediately after you do unset, for example, but probably would happen
"soon"). So actually figuring out if the object is referenced by any
other place could prove non-trivial, depending on the application
structure.
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/
Lars Schultz wrote:
I know that a lot of you may say: Why do need to do that?...and I'd have
to think for 3 days and then write for 4 days and would give up. It
seems like a nice solution to me and if any of you have an idea as to
how I could implement this differently, please feel free to point it out
to me.
Perhaps you could use your own reference counting?
Keep your "real" objects in private array and instead of returning them return
a simple object which would forward all methods and properties by
__get/__set/__call. The constructor would increase your internal refcount by
one, destructor would decrease it.
--
Paweł Stradomski
Perhaps you could use your own reference counting?
Keep your "real" objects in private array and instead of returning them return
a simple object which would forward all methods and properties by
__get/__set/__call. The constructor would increase your internal refcount by
one, destructor would decrease it.
I use those objects quite often as they are used to access the database
to manipulate or search for related data. It wouldn't perform well and
is actually not at all practicable because there are so many classes for
which I'd would have to copy the interface.
On 21 jan 2007 Lars Schultz wrote:
Perhaps you could use your own reference counting?
Keep your "real" objects in private array and instead of returning them
return a simple object which would forward all methods and properties by
__get/__set/__call. The constructor would increase your internal refcount
by one, destructor would decrease it.I use those objects quite often as they are used to access the database
to manipulate or search for related data. It wouldn't perform well and
is actually not at all practicable because there are so many classes for
which I'd would have to copy the interface.
I don't see any place where you'd have to change the interface - except for
the class which contains that private array; you can use the name of your
current class (MyObject)as the name of this new "forwarding" class and make a
new name for the class which would be a copy of your current class (eg.
MyObject_private). Therefore in all function definitions required class
specification doesn't need to change.
Well, perhaps you would have to change some "factory" class if you use one,
but that should be a one place - if you kept your code clean.
I think this solution is better, as you don't have to rely on internal
refcounts, which can be implemented in another way (or dropped altogether) in
future releases.
--
Paweł Stradomski