Dalam artikel ini, editor PHP Xigua akan memperkenalkan cara menggunakan refleksi untuk mengulang struktur secara rekursif dan menetapkan medan. Refleksi ialah ciri berkuasa dalam PHP yang membolehkan kami memperoleh dan memanipulasi maklumat seperti kelas, kaedah, sifat, dll. pada masa jalan. Struktur lelaran rekursif ialah kaedah pemprosesan biasa, yang boleh membantu kami merentasi dan mengendalikan struktur data yang kompleks. Dengan menggabungkan pantulan dan struktur lelaran rekursif, kita boleh mendapatkan dan menetapkan nilai medan dengan mudah, membolehkan pengaturcaraan yang lebih fleksibel dan cekap. Dalam kandungan berikut, kami akan memperkenalkan proses ini secara terperinci untuk membantu pembaca memahami dan menggunakan teknik ini dengan lebih baik.
Saya ingin membina program yang menggunakan refleksi untuk menetapkan medan struktur. Saya membuatnya berfungsi untuk medan peringkat atas, tetapi saya bergelut dengan medan struct bersarang. Bagaimana untuk mengulangi medan struct bersarang?
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)) } } }
Gunakan ciri ini:
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)) }
Fungsi findjsonfield mencari medan struktur melalui tag json medan:
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
Atas ialah kandungan terperinci Gunakan pantulan untuk mengulang struktur secara rekursif dan tetapkan medan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!