--- /dev/null
+<?php
+/**
+ * Copyright 2012-2017 Anthon Pang. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package WebDriver
+ *
+ * @author Anthon Pang <apang@softwaredevelopment.ca>
+ */
+
+namespace WebDriver;
+
+/**
+ * WebDriver\ServiceFactory class
+ *
+ * A service factory
+ *
+ * @package WebDriver
+ */
+final class ServiceFactory
+{
+ /**
+ * singleton
+ *
+ * @var \WebDriver\ServiceFactory
+ */
+ private static $instance;
+
+ /**
+ * @var array
+ */
+ protected $services;
+
+ /**
+ * @var array
+ */
+ protected $serviceClasses;
+
+ /**
+ * Private constructor
+ */
+ private function __construct()
+ {
+ $this->services = array();
+
+ $this->serviceClasses = array(
+ 'service.curl' => '\\WebDriver\\Service\\CurlService',
+ );
+ }
+
+ /**
+ * Get singleton instance
+ *
+ * @return \WebDriver\ServiceFactory
+ */
+ public static function getInstance()
+ {
+ if (!self::$instance) {
+ self::$instance = new self;
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Get service
+ *
+ * @param string $serviceName Name of service
+ *
+ * @return object
+ */
+ public function getService($serviceName)
+ {
+ if (!isset($this->services[$serviceName])) {
+ $className = $this->serviceClasses[$serviceName];
+
+ $this->services[$serviceName] = new $className;
+ }
+
+ return $this->services[$serviceName];
+ }
+
+ /**
+ * Set service
+ *
+ * @param string $serviceName Name of service
+ * @param object $service Service instance
+ */
+ public function setService($serviceName, $service)
+ {
+ $this->services[$serviceName] = $service;
+ }
+
+ /**
+ * Override default service class
+ *
+ * @param string $serviceName Name of service
+ * @param string $className Name of service class
+ */
+ public function setServiceClass($serviceName, $className)
+ {
+ if (substr($className, 0, 1) !== '\\') {
+ $className = '\\' . $className;
+ }
+
+ $this->serviceClasses[$serviceName] = $className;
+ $this->services[$serviceName] = null;
+ }
+}