public function ldapSearch(
        $baseDn,
        $filter,
        array $attributes = [],
        $scope = self::SCOPE_SUBTREE,
        $attrsOnly = false,
        $sizeLimit = 0,
        $timeLimit = 0,
        $deref = \LDAP_DEREF_NEVER
    ) {
        $function = $this->scopeToFunction($scope);
        // Support for parallel search
        $baseDn = (array)$baseDn;
        $filter = (array)$filter;

        // Sanity check... We need to do this ourselves because we are suppressing errors from the
        // ldap function call.
        if (count($baseDn) !== count($filter)) {
            // This is a programmer error - we should raise an error instead of catchable exception
            trigger_error('Array sizes of base DNs and filters do not match', E_USER_ERROR);
        }

        // Align the resources to match the amount of baseDns and filters provided
        $resources = array_fill(0, count($baseDn), $this->resource);

        $results = @$function(
            $resources,
            $baseDn,
            $filter,
            $attributes,
            $attrsOnly,
            $sizeLimit,
            $timeLimit,
            $deref
        );
        $this->verifyOperation();

        // Convert result resources into Result instances
        foreach ($results as $key => $result) {
            if (is_resource($result)) {
                $results[$key] = new Result($this, $result);
            } // Else - let it be whatever it was (probably FALSE - a failed search)
        }

        // If there is only one result, this was not a parallel search - return it directly
        return count($results) === 1 ? $results[0] : $results;
    }