module PhpSerialization
  class Serializer
    def run(object)
      case object
      when NilClass then
        "N;"
      when TrueClass then
        "b:1;"
      when FalseClass then
        "b:0;"
      when Integer then
        "i:#{object};"
      when Float then
        "d:#{object};"
      when String, Symbol then
        "s:#{object.to_s.length}:\"#{object}\";"
      when Array then
        idx   = -1
        items = object.map { |item| "#{run(idx += 1)}#{run(item)}" }.join
        "a:#{object.length}:{#{items}}"
      when Hash then
        items = object.map { |key,value| "#{run(key)}#{run(value)}" }.join
        "a:#{object.length}:{#{items}}"
      else
        klass_name = object.class.name
        
        if klass_name =~ /^Struct::/ && php_klass = object.instance_variable_get("@_php_class")
          klass_name = php_klass
        end
        
        attributes = object.instance_variables.map { |var_name| "#{run(var_name.gsub(/^@/, ''))}#{run(object.instance_variable_get(var_name))}" }
        "O:#{klass_name.length}:\"#{klass_name}\":#{object.instance_variables.length}:{#{attributes}}"
      end
    end  
  end
end
module PhpSerialization
  class Serializer
    def run(object)
      case object
      when NilClass then
        "N;"
      when TrueClass then
        "b:1;"
      when FalseClass then
        "b:0;"
      when Integer then
        "i:#{object};"
      when Float then
        "d:#{object};"
      when String, Symbol then
        "s:#{object.to_s.bytesize}:\"#{object}\";"
      when Array then
        idx   = -1
        items = object.map { |item| "#{run(idx += 1)}#{run(item)}" }.join
        "a:#{object.length}:{#{items}}"
      when Hash then
        items = object.map { |key,value| "#{run(key)}#{run(value)}" }.join
        "a:#{object.length}:{#{items}}"
      else
        klass_name = object.class.name

        if klass_name =~ /^Struct::/ && php_klass = object.instance_variable_get("@_php_class")
          klass_name = php_klass
        end

        attributes = object.instance_variables.map { |var_name| "#{run(var_name.gsub(/^@/, ''))}#{run(object.instance_variable_get(var_name))}" }
        "O:#{klass_name.length}:\"#{klass_name}\":#{object.instance_variables.length}:{#{attributes}}"
      end
    end
  end
end

Fix serializing multibyte character length issue.
Fix serializing multibyte character length issue.

When developer serialize multibyte character, it seems serialized, but
unserialize it through php fails. It is because php serialization
expects sting byte length, but `String#length` is just length of string
in ruby >= 1.9.
To fix the issue, changed to use `String#bytesize` in `Serializer#run`.
