* sort/Heap.php

<?php
/**
 * Created by PhpStorm.
 * User: Mch
 * Date: 2018/11/4
 * Time: 10:12 PM
 */

namespace sort;

class Heap {
    /** @var Comparator */
    protected $comparator;

    public function __construct(Comparator $c) {
        $this->comparator = $c;
    }

    private static function leftChild($i) {
        return ($i<<1) + 1;
    }

    private function percDown(array &$a, int $i, int $n) {
        for ($tmp = $a[$i]; self::leftChild($i) < $n; $i = $child) {
            $child = self::leftChild($i);
            if ($child !== $n - 1 && $this->comparator->greeterThan(
                    $a[$child+1],$a[$child])) {
                $child++;
            }
            if ($this->comparator->lessThan($tmp, $a[$child])) {
                $a[$i] = $a[$child];
            } else {
                break;
            }
        }
        $a[$i] = $tmp;
    }

    public function sort(array &$a) {
        $n = count($a);
        // build heap
        for ($i = $n >> 1; $i >= 0; $i--) {
            self::percDown($a, $i, $n);
        }
        for ($i = $n-1; $i > 0; $i--) {
            // delete max
            ArrayUtil::exch($a, 0, $i);
            self::percDown($a, 0, $i);
        }
    }
}

* sort/Comparator.php

<?php
namespace sort;

class Comparator {
    /** @var callable */
    protected $compare;

    public function __construct(callable $compareFunction = null) {
        if (is_null($compareFunction)) {
            $this->compare = function($a, $b) {
                if ($a === $b) {return 0;}
                return $a > $b ? 1 : -1;
            };
            return;
        }
        $this->compare = $compareFunction;
    }
    /*** @return bool */
    public function equal($a, $b) {
        return call_user_func($this->compare, $a, $b) === 0;
    }

    /*** @return bool */
    public function lessThan($a, $b) {
        return call_user_func($this->compare, $a, $b) < 0;
    }

    /*** @return bool */
    public function greeterThan($a, $b) {
        return call_user_func($this->compare, $a, $b) > 0;
    }

    /*** @return bool */
    public function lessThanOrEqual($a, $b) {
        return $this->lessThan($a, $b) || $this->equal($a, $b);
    }

    /*** @return bool */
    public function greeterThanOrEqual($a, $b) {
        return $this->greeterThan($a, $b) || $this->equal($a, $b);
    }

    public function reverse() {
        $compareOriginal = $this->compare;
        $this->compare = function ($a, $b) use ($compareOriginal) {
            return $compareOriginal($b, $a);
        };
    }
}

* sort/ArrayUtil.php

<?php

namespace sort;

class ArrayUtil {
    public static function shuffle(array &$a) {
        $m = count($a);
        while ($m) {
            $i = rand(0, --$m);
            self::exch($a, $i, $m);
        }
    }

    public static function exch(array &$a, $i, $j) {
        if ($i === $j) {return;}
        $a[$i] = $a[$i] ^ $a[$j];
        $a[$j]= $a[$i] ^ $a[$j];
        $a[$i] = $a[$i] ^ $a[$j];
    }

    public static function some(array $a, callable $c) {
        for ($i = 0, $n = count($a); $i < $n; $i++)
            if ($c( $a[$i] ))
                return true;
        return false;
    }

    public static function isSorted(array $a, callable $cmp) {
        for ($i = 1, $n = count($a); $i < $n; $i++)
            if ($cmp($a[$i], $a[$i-1]) < 0)
                return false;
        return true;
    }
}

* autoload.php

<?php
$prefixList = ['sort', 'dp'];

array_walk($prefixList, function($prefix) {
    spl_autoload_register(function($class) use ($prefix) {
        $base_dir = __DIR__ . DIRECTORY_SEPARATOR. str_replace('\\', '/', $prefix);
        $len = strlen($prefix);
        if (strncmp($prefix, $class, $len) !== 0) {
            return;
        }
        $relative_class = substr($class, $len);
        $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
        if (file_exists($file)) {
            require $file;
        }
    });
}, null);
<?php
// index.php

include 'autoload.php';

use sort\Heap;
use sort\Comparator;
use sort\ArrayUtil;

$s = "HEAPSORTEXAMPLE";
$a = str_split($s);

$heap = new Heap(new Comparator(strcmp));
$heap->sort($a);
echo implode('', $a).PHP_EOL;
var_dump(ArrayUtil::isSorted($a, strcmp)); // bool(true)

* test:

php index.php

AAEEEHLMOPPRSTX

bool(true)