public function parse(string $string): self
    {
        // if the $string is not valid interval, short-circuit
        $pattern = '/^[\[\(]-?(\d*[\.]?\d+|INF), -?(\d*[\.]?\d+|INF)[\]\)]$/';
        if ( ! preg_match($pattern, $string)) {
            throw new InvalidArgumentException(
                __METHOD__ . "() expects parameter one, string, to be a valid "
                    . "interval; see the README for details"
            );
        }
        
        // otherwise, check the boundaries
        $this->isLowerInclusive = substr($string, 0, 1) === '[';
        $this->isUpperInclusive = substr($string, -1, 1) === ']';
        
        // get the endpoints
        $endpoints = explode($this->separator, substr($string, 1, -1));
        
        // loop through the endpoints
        foreach ($endpoints as &$endpoint) {
            // if the endpoint is negative or positive infinity, convert the value 
            //     to the PHP constant; otherwise, cast the value to int or float
            //
            if ($endpoint === self::INFINITY_NEGATIVE) {
                $endpoint = -INF;
            } elseif ($endpoint === self::INFINITY_POSITIVE) {
                $endpoint = INF;
            } else {
                $endpoint = +$endpoint;
            }    
        }
        
        // if the endpoints are out of order, short-circuit
        if ($endpoints[1] < $endpoints[0]) {
            throw new InvalidArgumentException(
                __METHOD__ . "() expects parameter one, string, to be a valid "
                    . "interval, however, the upper bound appears to be greater "
                    . "than the lower bound"
            );
        }
        
        // if the endpoints are equal, the boundaries must match
        if (
            $endpoints[0] == $endpoints[1] 
            && $this->isLowerInclusive !== $this->isUpperInclusive
        ) {
            throw new InvalidArgumentException(
                __METHOD__ . "() expects parameter one, string, to be a valid "
                    . "interval, however, the endpoints are the same but the "
                    . "boundaries are different"
            );
        }
        
        // otherwise, set the endpoints
        $this->lower = $endpoints[0];
        $this->upper = $endpoints[1];
        
        return $this;
    }