private function getPublicProperties()
    {
        $class = get_class($this);

        // cache class public property names since reflection is expensive
        if (!array_key_exists($class, self::$public_properties_cache)) {
            $public_properties = array();

            $reflector = new ReflectionClass($class);
            foreach ($reflector->getProperties() as $property) {
                if ($property->isPublic() && !$property->isStatic()) {
                    $public_properties[] = $property->getName();
                }
            }

            self::$public_properties_cache[$class] = $public_properties;
        }

        // get property values for this object
        $names = self::$public_properties_cache[$class];
        $properties = array();
        foreach ($names as $name) {
            $properties[$name] = $this->$name;
        }

        return $properties;
    }