See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
1 <?php 2 3 /** 4 * CFTypeDetector 5 * Interface for converting native PHP data structures to CFPropertyList objects. 6 * @author Rodney Rehm <rodney.rehm@medialize.de> 7 * @author Christian Kruse <cjk@wwwtech.de> 8 * @package plist 9 * @subpackage plist.types 10 * @example example-create-02.php Using {@link CFTypeDetector} 11 * @example example-create-03.php Using {@link CFTypeDetector} with {@link CFDate} and {@link CFData} 12 * @example example-create-04.php Using and extended {@link CFTypeDetector} 13 */ 14 15 namespace CFPropertyList; 16 use \DateTime, \Iterator; 17 18 class CFTypeDetector { 19 20 /** 21 * flag stating if all arrays should automatically be converted to {@link CFDictionary} 22 * @var boolean 23 */ 24 protected $autoDictionary = false; 25 26 /** 27 * flag stating if exceptions should be suppressed or thrown 28 * @var boolean 29 */ 30 protected $suppressExceptions = false; 31 32 /** 33 * name of a method that will be used for array to object conversations 34 * @var callable 35 */ 36 protected $objectToArrayMethod = null; 37 38 /** 39 * flag stating if "123.23" should be converted to float (true) or preserved as string (false) 40 * @var boolean 41 */ 42 protected $castNumericStrings = true; 43 44 45 /** 46 * Create new CFTypeDetector 47 * @param array $options Configuration for casting values [autoDictionary, suppressExceptions, objectToArrayMethod, castNumericStrings] 48 */ 49 public function __construct(array $options=array()) { 50 //$autoDicitionary=false,$suppressExceptions=false,$objectToArrayMethod=null 51 foreach ($options as $key => $value) { 52 if (property_exists($this, $key)) { 53 $this->$key = $value; 54 } 55 } 56 } 57 58 /** 59 * Determine if an array is associative or numerical. 60 * Numerical Arrays have incrementing index-numbers that don't contain gaps. 61 * @param array $value Array to check indexes of 62 * @return boolean true if array is associative, false if array has numeric indexes 63 */ 64 protected function isAssociativeArray($value) { 65 $numericKeys = true; 66 $i = 0; 67 foreach($value as $key => $v) { 68 if($i !== $key) { 69 $numericKeys = false; 70 break; 71 } 72 $i++; 73 } 74 return !$numericKeys; 75 } 76 77 /** 78 * Get the default value 79 * @return CFType the default value to return if no suitable type could be determined 80 */ 81 protected function defaultValue() { 82 return new CFString(); 83 } 84 85 /** 86 * Create CFType-structure by guessing the data-types. 87 * {@link CFArray}, {@link CFDictionary}, {@link CFBoolean}, {@link CFNumber} and {@link CFString} can be created, {@link CFDate} and {@link CFData} cannot. 88 * <br /><b>Note:</b>Distinguishing between {@link CFArray} and {@link CFDictionary} is done by examining the keys. 89 * Keys must be strictly incrementing integers to evaluate to a {@link CFArray}. 90 * Since PHP does not offer a function to test for associative arrays, 91 * this test causes the input array to be walked twice and thus work rather slow on large collections. 92 * If you work with large arrays and can live with all arrays evaluating to {@link CFDictionary}, 93 * feel free to set the appropriate flag. 94 * <br /><b>Note:</b> If $value is an instance of CFType it is simply returned. 95 * <br /><b>Note:</b> If $value is neither a CFType, array, numeric, boolean nor string, it is omitted. 96 * @param mixed $value Value to convert to CFType 97 * @param boolean $autoDictionary if true {@link CFArray}-detection is bypassed and arrays will be returned as {@link CFDictionary}. 98 * @return CFType CFType based on guessed type 99 * @uses isAssociativeArray() to check if an array only has numeric indexes 100 */ 101 public function toCFType($value) { 102 switch(true) { 103 case $value instanceof CFType: 104 return $value; 105 break; 106 107 case is_object($value): 108 // DateTime should be CFDate 109 if(class_exists( 'DateTime' ) && $value instanceof DateTime){ 110 return new CFDate($value->getTimestamp()); 111 } 112 113 // convert possible objects to arrays, arrays will be arrays 114 if($this->objectToArrayMethod && is_callable(array($value, $this->objectToArrayMethod))){ 115 $value = call_user_func( array( $value, $this->objectToArrayMethod ) ); 116 } 117 118 if(!is_array($value)){ 119 if($this->suppressExceptions) 120 return $this->defaultValue(); 121 122 throw new PListException('Could not determine CFType for object of type '. get_class($value)); 123 } 124 /* break; omitted */ 125 126 case $value instanceof Iterator: 127 case is_array($value): 128 // test if $value is simple or associative array 129 if(!$this->autoDictionary) { 130 if(!$this->isAssociativeArray($value)) { 131 $t = new CFArray(); 132 foreach($value as $v) $t->add($this->toCFType($v)); 133 return $t; 134 } 135 } 136 137 $t = new CFDictionary(); 138 foreach($value as $k => $v) $t->add($k, $this->toCFType($v)); 139 140 return $t; 141 break; 142 143 case is_bool($value): 144 return new CFBoolean($value); 145 break; 146 147 case is_null($value): 148 return new CFString(); 149 break; 150 151 case is_resource($value): 152 if ($this->suppressExceptions) { 153 return $this->defaultValue(); 154 } 155 156 throw new PListException('Could not determine CFType for resource of type '. get_resource_type($value)); 157 break; 158 159 case is_numeric($value): 160 if (!$this->castNumericStrings && is_string($value)) { 161 return new CFString($value); 162 } 163 164 return new CFNumber($value); 165 break; 166 167 case is_string($value): 168 if(strpos($value, "\x00") !== false) { 169 return new CFData($value); 170 } 171 return new CFString($value); 172 173 break; 174 175 default: 176 if ($this->suppressExceptions) { 177 return $this->defaultValue(); 178 } 179 180 throw new PListException('Could not determine CFType for '. gettype($value)); 181 break; 182 } 183 } 184 185 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body