Skip to content

Commit

Permalink
Add tag option for omitting serialization of nil pointer values (#22)
Browse files Browse the repository at this point in the history
Add omitnilptr tag option for omitting encoding of nil pointers. This prevents panicking when attempting encoding struct with nil pointer fields.
  • Loading branch information
reiswindy authored Mar 13, 2021
1 parent 7f8a11c commit 5004667
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 13 deletions.
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ go get -u github.com/elliotchance/phpserialize
package main

import (
"github.com/elliotchance/phpserialize"
"fmt"
"github.com/elliotchance/phpserialize"
)

func main() {
Expand All @@ -35,3 +35,37 @@ func main() {
fmt.Println(in)
}
```

### Using struct field tags for marshalling

```go
package main

import (
"fmt"
"github.com/elliotchance/phpserialize"
)

type MyStruct struct {
// Will be marhsalled as my_purpose
MyPurpose string `php:"my_purpose"`
// Will be marshalled as my_motto, and only if not a nil pointer
MyMotto *string `php:"my_motto,omitnilptr"`
// Will not be marshalled
MySecret string `php:"-"`
}

func main() {
my := MyStruct{
MyPurpose: "No purpose",
MySecret: "Has a purpose",
}

out, err := phpserialize.Marshal(my, nil)
if err != nil {
panic(err)
}

fmt.Println(out)
}
```
15 changes: 10 additions & 5 deletions serialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,17 @@ func MarshalStruct(input interface{}, options *MarshalOptions) ([]byte, error) {

visibleFieldCount++

// Note: since we can only export fields that are public (start
// with an uppercase letter) we must change it to lower case. If
// you really do want it to be upper case you will have to wait
// for when tags are supported on individual fields.
fieldName := typeOfValue.Field(i).Tag.Get("php")
fieldName, fieldOptions := parseTag(typeOfValue.Field(i).Tag.Get("php"))

if fieldOptions.Contains("omitnilptr") {
if f.Kind() == reflect.Ptr && f.IsNil() {
visibleFieldCount--
continue
}
}

if fieldName == "-" {
visibleFieldCount--
continue
} else if fieldName == "" {
fieldName = lowerCaseFirstLetter(typeOfValue.Field(i).Name)
Expand Down
15 changes: 8 additions & 7 deletions serialize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ type structTag struct {
Foo Struct2 `php:"bar"`
Bar int `php:"foo"`
hidden bool
Balu string `php:"baz"`
Ignored string `php:"-"`
Balu string `php:"baz"`
Ignored string `php:"-"`
Nilptr *Struct2 `php:",omitnilptr"`
}

type Struct2 struct {
Expand Down Expand Up @@ -134,9 +135,9 @@ var marshalTests = map[string]marshalTest{
},

// encode object (struct with tags)
"structTag{Bar int, Foo Struct2{Qux float64}, hidden bool, Balu string}": {
structTag{Struct2{1.23}, 10, true, "yay", ""},
[]byte("O:9:\"structTag\":4:{s:3:\"bar\";O:7:\"Struct2\":1:{s:3:\"qux\";d:1.23;}s:3:\"foo\";i:10;s:3:\"baz\";s:3:\"yay\";}"),
"structTag{Bar int, Foo Struct2{Qux float64}, hidden bool, Balu string, Nilptr <nil>}": {
structTag{Struct2{1.23}, 10, true, "yay", "", nil},
[]byte("O:9:\"structTag\":3:{s:3:\"bar\";O:7:\"Struct2\":1:{s:3:\"qux\";d:1.23;}s:3:\"foo\";i:10;s:3:\"baz\";s:3:\"yay\";}"),
nil,
},

Expand Down Expand Up @@ -166,8 +167,8 @@ func TestMarshal(t *testing.T) {
}

if !reflect.DeepEqual(result, test.output) {
t.Errorf("Expected '%v', got '%v'", string(result),
string(test.output))
t.Errorf("Expected '%v', got '%v'", string(test.output),
string(result))
}
})
}
Expand Down
31 changes: 31 additions & 0 deletions tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package phpserialize

import "strings"

type tagOptions string

func parseTag(tag string) (string, tagOptions) {
if i := strings.Index(tag, ","); i != -1 {
return tag[:i], tagOptions(tag[i+1:])
}
return tag, ""
}

func (o tagOptions) Contains(option string) bool {
if len(o) == 0 {
return false
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == option {
return true
}
s = next
}
return false
}

0 comments on commit 5004667

Please sign in to comment.