PHP Annotations und Reflections
$prop->setAccessible(true);
Wenn man dann noch neben den skalaren Typen eine extra Behandlung für Array-Inhalte und Objekte einbaut, kann man sich ganz einfach einen rekursiven JSON-Encoder bauen, der auch mit normalen Beans mit Gettern und Settern zurecht kommt und man keine zusätzlichen DTOs mehr extra anlegen muss.
class XWJSONConverter{
public function __construct(){
}
public function convert($value,$level=0,$name=null,$firstInLine=true,$result=""){
$opening=false;
if($level==0 && $name!=null){
$result.="{";
$opening=true;
}
if(is_scalar($value)){
if(!$firstInLine){
$result.= ",";
}
if($name!=null){
$result.= '"'.$name.'":';
}
$result.= json_encode($value);
}
else if(is_array($value)){
if($name!=null){
$result.= '"'.$name.'":';
}
$result.= "[";
$i=0;
foreach($value as $val){
$result=$this->convert($val,$level+1,null,$i==0,$result);
$i++;
}
$result.= "]";
}
else if(is_object($value)){
if(!$firstInLine){
$result.= ",";
}
if($name!=null){
$result.= '"'.$name.'":';
}
$result.= "{";
$ref=new ReflectionClass(get_class($value));
$props=$ref->getProperties();
$cnt=count($props);
for($i=0;$i<$cnt;$i++){
$prop=$props[$i];
$doc=trim($prop->getDocComment());
if(!preg_match("/@json_transient/i",$doc)){
$prop->setAccessible(true);
$name=$prop->getName();
if($prop->isPrivate() || $prop->isProtected()){
$name=preg_replace("/^_/","",$name);
}
$result=$this->convert($prop->getValue($value),$level+1,$name,$i==0,$result);
}
}
$result.= "}";
}
else if(is_null($value)){
if (!$firstInLine) {
$result .= ',';
}
if ($name != null) {
$result .= '"' . $name . '":';
}
$result .= 'null';
}
if($opening){
$result.="}";
}
return $result;
}
}
Ein Decoder war mir jetzt nciht wirklich wichtig, da in meinen Anwendungsfällen PHP eigetnlich immer nur JSON für REST-APIs generiert und auf JavaScript-Seite, das decodieren in eine Objekt-Struktur ohne Probleme dann wieder möglich ist. Da sind private und public nicht mehr wichtig.
Was hier noch interessant sein könnte ist mein Versuch mit Annotations in PHP zu arbeiten. Wenn man verhindern will, dass ein Attribute mit nach JSON encodiert wird, kann man das damit verhindern:
class Test{
private $toJSON="ok";
/**
* @json_transient
*/
private $notToJSON="ne";
}
Damit wird im JSON-String nur das erste Attribute auftauchen.