php editor Xigua will introduce how to use reflection recursion to iterate the structure and set the fields in this article. Reflection is a powerful feature in PHP that allows us to obtain and manipulate information such as classes, methods, properties, etc. at runtime. Recursive iteration structure is a common processing method, which can help us traverse and operate complex data structures. By combining reflection and recursive iteration structures, we can easily get and set the value of a field, allowing for more flexible and efficient programming. In the following content, we will introduce this process in detail to help readers better understand and apply this technique.
I want to build a program that uses reflection to set the fields of a structure. I got it to work for top-level fields, but I'm struggling with nested struct fields. How to iterate over nested struct fields?
type Payload struct { Type string `json:"type"` SubItem *SubItem `json:"sub_item"` } type SubItem struct { Foo string `json:"foo"` } func main() { var payload Payload setValue(&payload, "type", "test1") setValue(&payload, "sub_item.foo", "test2") } func setValue(structPtr interface{}, key string, value string) { structValue := reflect.Indirect(reflect.ValueOf(structPtr)) for i, subkey := range strings.Split(key, ".") { isLast := i == len(strings.Split(key, "."))-1 var found bool // this line is crashing with "reflect: call of reflect.Value.NumField on zero Value" for i := 0; i < structValue.NumField(); i++ { field := structValue.Type().Field(i) jsonTags := strings.Split(field.Tag.Get("json"), ",") if jsonTags[0] == subkey { found = true if isLast { if isLast { // last element // TODO set value fmt.Printf("TODO set value %s to %v", value, structValue) structValue = reflect.Indirect(reflect.ValueOf(structPtr)) } } else { structValue = reflect.Indirect(reflect.ValueOf(structValue.Field(i).Interface())) } break } } if !found { panic(fmt.Errorf("failed to find field %s", key)) } } }
Use this function:
func setvalue(p interface{}, key string, value interface{}) { v := reflect.valueof(p) // loop through the names in key to find the target field. for _, name := range strings.split(key, ".") { // if the value is pointer, then // - allocate value if ptr is nil. // - indirect ptr for v.kind() == reflect.ptr { if v.isnil() { v.set(reflect.new(v.type().elem())) } v = v.elem() } // we expect that the value is struct. find the // named field. v = findjsonfield(v, name) if !v.isvalid() { panic(fmt.sprintf("could not find field %s", key)) } } // set the field. v.set(reflect.valueof(value)) }
Function findjsonfield finds the structure field through the json tag of the field:
func findJSONField(v reflect.Value, name string) reflect.Value { t := v.Type() for i := 0; i < v.NumField(); i++ { if tag, _, _ := strings.Cut(t.Field(i).Tag.Get("json"), ","); tag == name { return v.Field(i) } } return reflect.Value{} }
https://www.php.cn/link/e4848ea6b69df2c66c87e2877e74726b
The above is the detailed content of Use reflection to iterate over a structure recursively and set fields. For more information, please follow other related articles on the PHP Chinese website!