Heim  >  Artikel  >  Backend-Entwicklung  >  Verwenden Sie Reflection, um eine Struktur rekursiv zu durchlaufen und Felder festzulegen

Verwenden Sie Reflection, um eine Struktur rekursiv zu durchlaufen und Felder festzulegen

WBOY
WBOYnach vorne
2024-02-10 20:45:10585Durchsuche

Verwenden Sie Reflection, um eine Struktur rekursiv zu durchlaufen und Felder festzulegen

Der PHP-Editor Xigua stellt in diesem Artikel vor, wie man die Reflexionsrekursion zum Iterieren der Struktur und zum Festlegen von Feldern verwendet. Reflection ist eine leistungsstarke Funktion in PHP, die es uns ermöglicht, Informationen wie Klassen, Methoden, Eigenschaften usw. zur Laufzeit abzurufen und zu bearbeiten. Die rekursive Iterationsstruktur ist eine gängige Verarbeitungsmethode, die uns beim Durchlaufen und Betreiben komplexer Datenstrukturen helfen kann. Durch die Kombination von Reflexions- und rekursiven Iterationsstrukturen können wir den Wert eines Felds einfach ermitteln und festlegen, was eine flexiblere und effizientere Programmierung ermöglicht. Im folgenden Inhalt stellen wir diesen Prozess im Detail vor, um den Lesern zu helfen, diese Technik besser zu verstehen und anzuwenden.

Frageninhalt

Ich möchte ein Programm erstellen, das mithilfe von Reflektion die Felder einer Struktur festlegt. Ich habe es für Felder der obersten Ebene zum Laufen gebracht, aber ich habe Probleme mit verschachtelten Strukturfeldern. Wie iteriere ich über verschachtelte Strukturfelder?

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))
        }
    }
}

Workaround

Verwenden Sie diese Funktion:

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))
}

Die Funktion findjsonfield findet das Strukturfeld über das JSON-Tag des Feldes:

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

Das obige ist der detaillierte Inhalt vonVerwenden Sie Reflection, um eine Struktur rekursiv zu durchlaufen und Felder festzulegen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen