<?php

function binary_mask(int $cidr_mask) {
    return bindec(str_pad(str_repeat('1', $cidr_mask), 32, '0'));
}

function cidr_mask(int $binary_mask) {
    return substr_count(decbin($binary_mask), '1');
}


Class Network {
    public int $address;
    public int $mask;
    public string $name = "";

    public function __construct(int $address, int $cidr_mask, string $name = "", string $description = "") {
        $this->mask = binary_mask($cidr_mask);
        $this->address = $address & $this->mask;
        $this->name = $name;
    }

    public function __toString(): string {
        return long2ip($this->address) . " / " . cidr_mask($this->mask);
    }

    public function __debugInfo(): array {
        return [
            "name" => $this->name,
            "ip_adress" => long2ip($this->address),
            "cidr_mask" => cidr_mask($this->mask),
        ];
    }

    public function contains(Network $other) {
        return ($other->address & $this->mask) == $this->address;
    }
}

$networks = [
    new Network(ip2long("10.75.0.0"), 16, "Paris"),
    new Network(ip2long("10.94.0.0"), 16, "Val-de-Marne"),
    new Network(ip2long("10.232.0.0"), 16, "DiRIF"),
    new Network(ip2long("10.75.128.0"), 22, "Miollis"),
    new Network(ip2long("10.75.128.0"), 24, "Serveurs"),
    new Network(ip2long("10.75.129.0"), 24, "Data"),
    new Network(ip2long("10.75.8.0"), 22, "Crillon"),
    new Network(ip2long("10.94.8.0"), 22, "Créteil Archives"),
    new Network(ip2long("10.232.160.0"), 22, "Créteil l'Echat"),
];

$subnetworks = [];
foreach ($networks as $network) {
    $subnetworks[] = ["network" => $network, "subnetworks" => []];
}

usort($subnetworks, function($a, $b) {
    return $b["network"]->mask <=> $a["network"]->mask;
});

$networks_tree = [];

while (count($subnetworks)) {
    ["network" => $network1, "subnetworks" => $subnetworks1] = array_shift($subnetworks);
    foreach($subnetworks as ["network" => $network2, "subnetworks" => &$subnetworks2]) {
        if ($network2->contains($network1)) {
            $subnetworks2[] = ["network" => $network1, "subnetworks" => $subnetworks1];
            continue 2;
        }
    }
    $networks_tree[] = ["network" => $network1, "subnetworks" => $subnetworks1];
}
var_dump($networks_tree);