1<?php 2/* 3 * This file is part of the Environment package. 4 * 5 * (c) Sebastian Bergmann <sebastian@phpunit.de> 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11namespace SebastianBergmann\Environment; 12 13/** 14 * Utility class for HHVM/PHP environment handling. 15 */ 16class Runtime 17{ 18 /** 19 * @var string 20 */ 21 private static $binary; 22 23 /** 24 * Returns true when Xdebug is supported or 25 * the runtime used is PHPDBG (PHP >= 7.0). 26 * 27 * @return bool 28 */ 29 public function canCollectCodeCoverage() 30 { 31 return $this->hasXdebug() || $this->hasPHPDBGCodeCoverage(); 32 } 33 34 /** 35 * Returns the path to the binary of the current runtime. 36 * Appends ' --php' to the path when the runtime is HHVM. 37 * 38 * @return string 39 */ 40 public function getBinary() 41 { 42 // HHVM 43 if (self::$binary === null && $this->isHHVM()) { 44 if ((self::$binary = getenv('PHP_BINARY')) === false) { 45 self::$binary = PHP_BINARY; 46 } 47 48 self::$binary = escapeshellarg(self::$binary) . ' --php'; 49 } 50 51 // PHP >= 5.4.0 52 if (self::$binary === null && defined('PHP_BINARY')) { 53 if (PHP_BINARY !== '') { 54 self::$binary = escapeshellarg(PHP_BINARY); 55 } 56 } 57 58 // PHP < 5.4.0 59 if (self::$binary === null) { 60 if (PHP_SAPI == 'cli' && isset($_SERVER['_'])) { 61 if (strpos($_SERVER['_'], 'phpunit') !== false) { 62 $file = file($_SERVER['_']); 63 64 if (strpos($file[0], ' ') !== false) { 65 $tmp = explode(' ', $file[0]); 66 self::$binary = escapeshellarg(trim($tmp[1])); 67 } else { 68 self::$binary = escapeshellarg(ltrim(trim($file[0]), '#!')); 69 } 70 } elseif (strpos(basename($_SERVER['_']), 'php') !== false) { 71 self::$binary = escapeshellarg($_SERVER['_']); 72 } 73 } 74 } 75 76 if (self::$binary === null) { 77 $possibleBinaryLocations = [ 78 PHP_BINDIR . '/php', 79 PHP_BINDIR . '/php-cli.exe', 80 PHP_BINDIR . '/php.exe' 81 ]; 82 83 foreach ($possibleBinaryLocations as $binary) { 84 if (is_readable($binary)) { 85 self::$binary = escapeshellarg($binary); 86 break; 87 } 88 } 89 } 90 91 if (self::$binary === null) { 92 self::$binary = 'php'; 93 } 94 95 return self::$binary; 96 } 97 98 /** 99 * @return string 100 */ 101 public function getNameWithVersion() 102 { 103 return $this->getName() . ' ' . $this->getVersion(); 104 } 105 106 /** 107 * @return string 108 */ 109 public function getName() 110 { 111 if ($this->isHHVM()) { 112 return 'HHVM'; 113 } elseif ($this->isPHPDBG()) { 114 return 'PHPDBG'; 115 } else { 116 return 'PHP'; 117 } 118 } 119 120 /** 121 * @return string 122 */ 123 public function getVendorUrl() 124 { 125 if ($this->isHHVM()) { 126 return 'http://hhvm.com/'; 127 } else { 128 return 'https://secure.php.net/'; 129 } 130 } 131 132 /** 133 * @return string 134 */ 135 public function getVersion() 136 { 137 if ($this->isHHVM()) { 138 return HHVM_VERSION; 139 } else { 140 return PHP_VERSION; 141 } 142 } 143 144 /** 145 * Returns true when the runtime used is PHP and Xdebug is loaded. 146 * 147 * @return bool 148 */ 149 public function hasXdebug() 150 { 151 return ($this->isPHP() || $this->isHHVM()) && extension_loaded('xdebug'); 152 } 153 154 /** 155 * Returns true when the runtime used is HHVM. 156 * 157 * @return bool 158 */ 159 public function isHHVM() 160 { 161 return defined('HHVM_VERSION'); 162 } 163 164 /** 165 * Returns true when the runtime used is PHP without the PHPDBG SAPI. 166 * 167 * @return bool 168 */ 169 public function isPHP() 170 { 171 return !$this->isHHVM() && !$this->isPHPDBG(); 172 } 173 174 /** 175 * Returns true when the runtime used is PHP with the PHPDBG SAPI. 176 * 177 * @return bool 178 */ 179 public function isPHPDBG() 180 { 181 return PHP_SAPI === 'phpdbg' && !$this->isHHVM(); 182 } 183 184 /** 185 * Returns true when the runtime used is PHP with the PHPDBG SAPI 186 * and the phpdbg_*_oplog() functions are available (PHP >= 7.0). 187 * 188 * @return bool 189 */ 190 public function hasPHPDBGCodeCoverage() 191 { 192 return $this->isPHPDBG() && function_exists('phpdbg_start_oplog'); 193 } 194} 195