3v4l.org

run code in 300+ PHP versions simultaneously
<?php class LinkedList { /** @var LinkedListBucket */ public $first; /** @var LinkedListBucket */ public $last; public $length = 0; public $min = PHP_INT_MAX; public function append(LinkedListBucket $bucket) { $this->last->next = $bucket; $this->last = $bucket; $this->length++; if ($bucket->codePoint < $this->min) { $this->min = $bucket->codePoint; } } public function insert(LinkedListBucket $after, LinkedListBucket $new) { $new->next = $after->next; $after->next = $new; if ($after === $this->last) { $this->last = $new; } $this->length++; if ($new->codePoint < $this->min) { $this->min = $new->codePoint; } } } class LinkedListBucket { public $pos; public $codePoint; public $raw; public $rawLen; /** @var LinkedListBucket */ public $next; public function __construct($pos, $codePoint, $raw = null, $rawLen = 0) { $this->pos = $pos; $this->codePoint = $codePoint; $this->raw = $raw; $this->rawLen = $rawLen; } } class Punycode { const BASE = 36; const T_MIN = 1; const T_MAX = 26; const SKEW = 38; const DAMP = 700; const INITIAL_BIAS = 72; const INITIAL_N = 128; private function decodeUtf8Character($input, $i, &$codePoint = null) { $input = array_values(unpack('C*', substr($input, $i, 4))); $count = count($input); switch (true) { case $count >= 2 && ($input[0] & 0xE0) === 0xC0 && ($input[1] & 0xC0) === 0x80: $codePoint = (($input[0] & 0x1F) << 6) | ($input[1] & 0x3F); return 2; case $count >= 3 && ($input[0] & 0xF0) === 0xE0 && (($input[1] ^ 0x40) & ($input[2] ^ 0x40) & 0xC0) === 0xC0: $codePoint = (($input[0] & 0x0F) << 12) | (($input[1] & 0x3F) << 6) | ($input[2] & 0x3F); return 3; case $count >= 4 && ($input[0] & 0xF8) === 0xF0 && (($input[1] ^ 0x40) & ($input[2] ^ 0x40) & ($input[3] ^ 0x40) & 0xC0) === 0xC0: $codePoint = (($input[0] & 0x07) << 18) | (($input[1] & 0x3F) << 12) | (($input[2] & 0x3F) << 6) | ($input[3] & 0x3F); return 4; } return 0; } private function encodeUtf8CodePoint($codePoint) { switch (true) { case $codePoint < 0x80: return pack('C*', $codePoint & 0x7F); case $codePoint < 0x0800: return pack('C*', (($codePoint & 0x07C0) >> 6) | 0xC0, ($codePoint & 0x3F) | 0x80); case $codePoint < 0x010000: return pack('C*', (($codePoint & 0xF000) >> 12) | 0xE0, (($codePoint & 0x0FC0) >> 6) | 0x80, ($codePoint & 0x3F) | 0x80); case $codePoint < 0x110000: return pack('C*', (($codePoint & 0x1C0000) >> 18) | 0xF0, (($codePoint & 0x03F000) >> 12) | 0x80, (($codePoint & 0x0FC0) >> 6) | 0x80, ($codePoint & 0x3F) | 0x80); } return false; } private function isDnsLabelChar($charCode) { return ($charCode >= 0x61 && $charCode <= 0x7A) // lower-case letter || ($charCode >= 0x30 && $charCode <= 0x39) // digit || $charCode === 0x2D // - || ($charCode >= 0x41 && $charCode <= 0x5A); // upper-case letter; } private function isPrintableLatin1Char($charCode) { return $charCode >= 0xA0; } private function adaptBias($delta, $numPoints, $first) { $delta = $first ? $delta / self::DAMP : $delta / 2; $delta += $delta / $numPoints; $div = self::BASE - self::T_MIN; $end = ($div * self::T_MAX) / 2; for ($k = 0; $delta > $end; $k += self::BASE) { $delta = (int)($delta / $div); } return $k + (($div + 1) * $delta) / ($delta + self::SKEW); } private function decodeDigit($digits, $index) { if (isset($digits[$index])) { $codePoint = ord($digits[$index]); if ($codePoint >= 0x61 && $codePoint <= 0x7A) { return $codePoint - 97; } else if ($codePoint >= 0x30 && $codePoint <= 0x39) { return $codePoint - 22; } } return false; } private function encodeDigit($digit) { if ($digit <= 25) { return $digit + 97; } else if ($digit <= 35) { return $digit + 22; } return false; } private function decodeLabel($input) { if (substr($input, 0, 4) !== 'xn--') { return $input; } $input = substr($input, 4); if (false !== $nonBasicCharsStart = strrpos($input, '-')) { $output = str_split(substr($input, 0, $nonBasicCharsStart), 1); $nonBasicChars = substr($input, $nonBasicCharsStart + 1); } else { $output = []; $nonBasicChars = $input; } $n = self::INITIAL_N; $bias = self::INITIAL_BIAS; $c = count($output) + 1; for ($i = $j = 0, $l = strlen($nonBasicChars); $j < $l; $i++) { $oldi = $i; $w = 1; for ($k = self::BASE;; $k+= self::BASE) { if (false === $digit = $this->decodeDigit($nonBasicChars, $j++)) { return false; } $i += $digit * $w; if ($k <= $bias) { $t = self::T_MIN; } else if ($k >= $bias + self::T_MAX) { $t = self::T_MAX; } else { $t = $k - $bias; } if ($digit < $t) { break; } $w *= (int) (self::BASE - $t); } $bias = $this->adaptBias($i - $oldi, $c, $oldi === 0); $n += (int)($i / $c); $i %= $c++; array_splice($output, $i, 0, [$this->encodeUtf8CodePoint($n)]); } return implode('', $output); } public function decode($input) { $output = []; foreach (explode('.', strtolower($input)) as $label) { if (false === $label = $this->decodeLabel($label)) { return false; } $output[] = $label; } return implode('.', $output); } private function getEncodingParts($input, &$output = null, &$nonBasicChars = null) { $isUtf8 = true; $output = []; $nonBasicChars = new LinkedList; for ($i = $p = 0, $l = strlen($input); $i < $l; $p++) { $charCode = ord($input[$i]); if ($charCode & 0x80) { if ($isUtf8) { if ($len = $this->decodeUtf8Character($input, $i, $codePoint)) { // undecoded data is stored for UTF-8 chars to facilitate conversion to latin1 if necessary $nonBasicChars->append(new LinkedListBucket($p, $codePoint, substr($input, $i, $len), $len)); $i += $len; } else { // not a valid UTF-8 code point, convert $nonBasicChars to latin1 representation if (!$this->isPrintableLatin1Char($charCode)) { return false; } $isUtf8 = false; if ($nonBasicChars->length > 0) { $offset = 0; $current = $nonBasicChars->first; do { $base = $current->pos; $current->pos += $offset; $current->codePoint = ord($current->raw[0]); for ($k = 1; $k < $current->rawLen; $k++) { $nonBasicChars->insert($current, new LinkedListBucket($base + ++$offset, ord($current->raw[$k]))); } } while($current = $current->next); } $nonBasicChars->append(new LinkedListBucket($i++, $charCode)); } } else if ($this->isPrintableLatin1Char($charCode)) { $nonBasicChars->append(new LinkedListBucket($i++, $charCode)); } else { return false; } } else if ($this->isDnsLabelChar($charCode)) { $output[] = $input[$i++]; } else { return false; } } return true; } private function encodeLabel($input) { /** @var LinkedList $nonBasicChars */ if (!$this->getEncodingParts($input, $output, $nonBasicChars)) { return false; } if ($nonBasicChars->length === 0) { return $input; } $n = self::INITIAL_N; $delta = 0; $bias = self::INITIAL_BIAS; $h = $b = count($output); if ($b > 0) { $output[] = '-'; } $current = $nonBasicChars->first; for ($l = $h + $nonBasicChars->length; $h < $l;) { $m = $nonBasicChars->min; $delta += ($m - $n) * ($h + 1); $n = $m; $i = 0; while ($i < $l && $current) { $c = $i === $current->pos ? $current->codePoint : ord($output[$i++]); if ($c < $n) { $delta++; } if ($c === $n) { $q = $delta; for ($k = self::BASE;; $k+= self::BASE) { if ($k <= $bias) { $t = self::T_MIN; } else if ($k >= $bias + self::T_MAX) { $t = self::T_MAX; } else { $t = $k - $bias; } if ($q < $t) { break; } $output[] = chr($this->encodeDigit($t + (($q - $t) % self::BASE - $t))); $q = ($q - $t) / (self::BASE - $t); } $output[] = chr($this->encodeDigit($q)); $bias = $this->adaptBias($delta, $h + 1, $h === $b); $delta = 0; $h++; } } $delta++; $n++; } return 'xn--' . implode('-', $output); } public function encode($input) { $output = []; foreach (explode('.', strtolower($input)) as $label) { if (false === $label = $this->encodeLabel($label)) { return false; } $output[] = $label; } return implode('.', $output); } } $punycode = new Punycode; $input = "www.xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n.com"; $decoded = $punycode->decode($input); $encoded = $punycode->encode($decoded); echo "Input: ", $input, "\n", "Decoded: ", $decoded, "\n", "Encoded: ", $encoded, "\n";

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.3.60.0140.00718.68
8.3.50.0140.00722.11
8.3.40.0040.01118.84
8.3.30.0090.00619.22
8.3.20.0080.00020.29
8.3.10.0080.00021.96
8.3.00.0080.00022.45
8.2.180.0040.01216.50
8.2.170.0060.01222.96
8.2.160.0100.01019.33
8.2.150.0040.00424.18
8.2.140.0040.00424.66
8.2.130.0070.01126.16
8.2.120.0050.00319.66
8.2.110.0030.00622.02
8.2.100.0040.01218.34
8.2.90.0080.00019.39
8.2.80.0000.00818.29
8.2.70.0030.00617.84
8.2.60.0030.00518.18
8.2.50.0000.00918.07
8.2.40.0030.00618.46
8.2.30.0080.00018.21
8.2.20.0080.00017.80
8.2.10.0030.00517.86
8.2.00.0090.00317.91
8.1.280.0120.00625.92
8.1.270.0030.00618.70
8.1.260.0050.00326.35
8.1.250.0080.00028.09
8.1.240.0030.00623.96
8.1.230.0110.00019.24
8.1.220.0030.00517.91
8.1.210.0040.00418.77
8.1.200.0060.00617.48
8.1.190.0040.00417.65
8.1.180.0040.00420.66
8.1.170.0080.00018.59
8.1.160.0040.00422.30
8.1.150.0050.00318.84
8.1.140.0090.00017.56
8.1.130.0000.00817.89
8.1.120.0070.00017.68
8.1.110.0030.00517.49
8.1.100.0040.00417.66
8.1.90.0050.00517.63
8.1.80.0030.00517.66
8.1.70.0000.00717.50
8.1.60.0040.00417.79
8.1.50.0040.00417.68
8.1.40.0040.00417.59
8.1.30.0030.00517.73
8.1.20.0030.00617.80
8.1.10.0040.00417.75
8.1.00.0030.00717.73
8.0.300.0030.00518.77
8.0.290.0040.00417.30
8.0.280.0040.00418.58
8.0.270.0040.00417.40
8.0.260.0040.00416.95
8.0.250.0040.00417.23
8.0.240.0040.00417.11
8.0.230.0000.00717.14
8.0.220.0040.00417.01
8.0.210.0030.00317.07
8.0.200.0000.00817.04
8.0.190.0050.00317.18
8.0.180.0000.00817.02
8.0.170.0000.00817.16
8.0.160.0040.00417.09
8.0.150.0040.00417.05
8.0.140.0000.00817.08
8.0.130.0030.00313.57
8.0.120.0000.00817.08
8.0.110.0030.00617.11
8.0.100.0060.00316.90
8.0.90.0080.00016.93
8.0.80.0000.01517.03
8.0.70.0000.00817.17
8.0.60.0000.00817.05
8.0.50.0040.00417.21
8.0.30.0110.00817.21
8.0.20.0120.01017.40
8.0.10.0090.00017.19
8.0.00.0110.01216.93
7.4.330.0002.01115.10
7.4.320.0032.00116.53
7.4.300.0002.00316.53
7.4.290.0031.99916.67
7.4.280.0071.99516.57
7.4.270.0031.99716.68
7.4.260.0002.00316.41
7.4.250.0002.00316.64
7.4.240.0022.00116.60
7.4.230.0031.99816.63
7.4.220.0101.98916.56
7.4.210.0161.98516.63
7.4.200.0032.00116.74
7.4.190.0071.99616.43
7.4.160.0271.98416.51
7.4.150.0101.98717.40
7.4.140.0331.97117.86
7.4.130.0131.98816.61
7.4.120.0331.96316.58
7.4.110.0102.44416.82
7.4.100.0132.45016.46
7.4.90.0262.42216.71
7.4.80.0102.44819.39
7.4.70.0162.44416.60
7.4.60.0181.51916.69
7.4.50.0072.49216.70
7.4.40.0102.48522.77
7.4.30.0612.23516.60
7.3.330.0031.99713.60
7.3.320.0002.00313.57
7.3.310.0002.00416.45
7.3.300.0071.99716.43
7.3.290.0161.99016.42
7.3.280.0101.99116.41
7.3.270.0101.98917.40
7.3.260.0421.92716.41
7.3.250.0231.97716.43
7.3.240.0161.95916.50
7.3.230.0162.44616.67
7.3.210.0172.45816.37
7.3.200.0132.45619.39
7.3.190.0232.44016.51
7.3.180.0072.45016.55
7.3.170.0132.44116.45
7.3.160.0102.45516.42
7.2.330.0132.44816.50
7.2.320.0482.32316.65
7.2.310.0102.43516.69
7.2.300.0072.46516.45
7.2.290.0162.43816.88
5.4.250.0302.40319.20
5.4.240.0132.40719.15
5.4.230.0232.41019.18
5.4.220.0132.45719.30
5.4.210.0172.37018.99
5.4.200.0272.40319.11
5.4.190.0232.39319.03
5.4.180.0232.43019.13
5.4.170.0202.41318.96
5.4.160.0132.45019.09
5.4.150.0302.38319.11
5.4.140.0272.38316.43
5.4.130.0132.44016.50
5.4.120.0302.38316.45
5.4.110.0432.38316.64
5.4.100.0172.36016.38
5.4.90.0301.92016.34
5.4.80.0231.91716.40
5.4.70.0071.97316.51
5.4.60.0471.92316.54
5.4.50.0532.02316.54
5.4.40.0172.18016.40
5.4.30.0772.32716.55
5.4.20.0172.34716.57
5.4.10.0332.34716.57
5.4.00.0172.40715.90
5.3.280.1870.04014.56
5.3.270.2000.04714.91
5.3.260.1930.04014.81
5.3.250.2070.04014.63
5.3.240.2030.04314.74
5.3.230.2070.04714.65
5.3.220.2030.04314.55
5.3.210.1930.04314.62
5.3.200.2000.04714.61
5.3.190.1970.03314.62
5.3.180.2100.03314.62
5.3.170.1830.03714.70
5.3.160.1900.03314.63
5.3.150.1970.03314.70
5.3.140.2130.04314.59
5.3.130.0630.04014.57
5.3.120.0030.04014.59
5.3.110.0030.03714.58
5.3.100.0070.05714.25
5.3.90.1870.03714.17
5.3.80.2170.04014.22
5.3.70.2300.04314.23
5.3.60.2230.04713.98
5.3.50.0030.04014.01
5.3.40.0070.06313.94
5.3.30.0900.03313.95
5.3.20.2230.03714.00
5.3.10.2070.03013.69
5.3.00.2030.03013.81

preferences:
29.99 ms | 401 KiB | 5 Q