src/Client.php
public function connect($uri)
    {
        if (strpos($uri, '://') === false) {
            $uri = 'tcp://' . $uri;
        }

        $parts = parse_url($uri);
        if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
            return Promise\reject(new InvalidArgumentException('Invalid target URI specified'));
        }

        $host = trim($parts['host'], '[]');
        $port = $parts['port'];

        if (strlen($host) > 255 || $port > 65535 || $port < 0 || (string)$port !== (string)(int)$port) {
            return Promise\reject(new InvalidArgumentException('Invalid target specified'));
        }

        // construct URI to SOCKS server to connect to
        $socksUri = $this->socksUri;

        // append path from URI if given
        if (isset($parts['path'])) {
            $socksUri .= $parts['path'];
        }

        // parse query args
        $args = array();
        if (isset($parts['query'])) {
            parse_str($parts['query'], $args);
        }

        // append hostname from URI to query string unless explicitly given
        if (!isset($args['hostname'])) {
            $args['hostname'] = $host;
        }

        // append query string
        $socksUri .= '?' . http_build_query($args, '', '&');

        // append fragment from URI if given
        if (isset($parts['fragment'])) {
            $socksUri .= '#' . $parts['fragment'];
        }

        // start TCP/IP connection to SOCKS server
        $connecting = $this->connector->connect($socksUri);

        $deferred = new Deferred(function ($_, $reject) use ($uri, $connecting) {
            $reject(new RuntimeException(
                'Connection to ' . $uri . ' cancelled while waiting for proxy (ECONNABORTED)',
                defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
            ));

            // either close active connection or cancel pending connection attempt
            $connecting->then(function (ConnectionInterface $stream) {
                $stream->close();
            });
            $connecting->cancel();
        });

        // handle SOCKS protocol once connection is ready
        // resolve plain connection once SOCKS protocol is completed
        $that = $this;
        $connecting->then(
            function (ConnectionInterface $stream) use ($that, $host, $port, $deferred, $uri) {
                $that->handleConnectedSocks($stream, $host, $port, $deferred, $uri);
            },
            function (Exception $e) use ($uri, $deferred) {
                $deferred->reject($e = new RuntimeException(
                    'Connection to ' . $uri . ' failed because connection to proxy failed (ECONNREFUSED)',
                    defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111,
                    $e
                ));

                // avoid garbage references by replacing all closures in call stack.
                // what a lovely piece of code!
                $r = new \ReflectionProperty('Exception', 'trace');
                $r->setAccessible(true);
                $trace = $r->getValue($e);
                foreach ($trace as &$one) {
                    foreach ($one['args'] as &$arg) {
                        if ($arg instanceof \Closure) {
                            $arg = 'Object(' . get_class($arg) . ')';
                        }
                    }
                }
                $r->setValue($e, $trace);
            }
        );

        return $deferred->promise();
    }
public function connect($uri)
    {
        if (strpos($uri, '://') === false) {
            $uri = 'tcp://' . $uri;
        }

        $parts = parse_url($uri);
        if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
            return Promise\reject(new InvalidArgumentException('Invalid target URI specified'));
        }

        $host = trim($parts['host'], '[]');
        $port = $parts['port'];

        if (strlen($host) > 255 || $port > 65535 || $port < 0 || (string)$port !== (string)(int)$port) {
            return Promise\reject(new InvalidArgumentException('Invalid target specified'));
        }

        // construct URI to SOCKS server to connect to
        $socksUri = $this->socksUri;

        // append path from URI if given
        if (isset($parts['path'])) {
            $socksUri .= $parts['path'];
        }

        // parse query args
        $args = array();
        if (isset($parts['query'])) {
            parse_str($parts['query'], $args);
        }

        // append hostname from URI to query string unless explicitly given
        if (!isset($args['hostname'])) {
            $args['hostname'] = $host;
        }

        // append query string
        $socksUri .= '?' . http_build_query($args, '', '&');

        // append fragment from URI if given
        if (isset($parts['fragment'])) {
            $socksUri .= '#' . $parts['fragment'];
        }

        // start TCP/IP connection to SOCKS server
        $connecting = $this->connector->connect($socksUri);

        $deferred = new Deferred(function ($_, $reject) use ($uri, $connecting) {
            $reject(new RuntimeException(
                'Connection to ' . $uri . ' cancelled while waiting for proxy (ECONNABORTED)',
                defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
            ));

            // either close active connection or cancel pending connection attempt
            $connecting->then(function (ConnectionInterface $stream) {
                $stream->close();
            });
            $connecting->cancel();
        });

        // handle SOCKS protocol once connection is ready
        // resolve plain connection once SOCKS protocol is completed
        $that = $this;
        $connecting->then(
            function (ConnectionInterface $stream) use ($that, $host, $port, $deferred, $uri) {
                $that->handleConnectedSocks($stream, $host, $port, $deferred, $uri);
            },
            function (Exception $e) use ($uri, $deferred) {
                $deferred->reject($e = new RuntimeException(
                    'Connection to ' . $uri . ' failed because connection to proxy failed (ECONNREFUSED)',
                    defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111,
                    $e
                ));

                // avoid garbage references by replacing all closures in call stack.
                // what a lovely piece of code!
                $r = new \ReflectionProperty('Exception', 'trace');
                $r->setAccessible(true);
                $trace = $r->getValue($e);
                foreach ($trace as &$one) {
                    foreach ($one['args'] as &$arg) {
                        if ($arg instanceof \Closure) {
                            $arg = 'Object(' . get_class($arg) . ')';
                        }
                    }
                }
                $r->setValue($e, $trace);
            }
        );

        return $deferred->promise();
    }
Establish a TCP/IP connection to the given target URI through the SOCKS server

Many higher-level networking protocols build on top of TCP. It you're dealing
with one such client implementation,  it probably uses/accepts an instance
implementing ReactPHP's `ConnectorInterface` (and usually its default `Connector`
instance). In this case you can also pass this `Connector` instance instead
to make this client implementation SOCKS-aware. That's it.

@param string $uri
@return PromiseInterface Promise<ConnectionInterface,Exception>