Datei-Klasse: return $this; How to...

Parantatatam

mag Cookies & Kekse
Hallo,

ich habe mich gerade mal an noch was anderes gewagt. Und zwar will ich die Dateisystem-Funktionen von PHP ein wenig ausschmücken. Also ich will zum Beispiel so was hier dann aufrufen:
PHP:
$a = new File();
$a->file('alter_name.txt')->rename('neuer_name.txt');
Das ist ja möglich indem ich per return die Klassenvariable $this ausgebe. Nun ist aber das Problem, dass es auch mal passieren kann, dass ich nur die Methode $a->file() so aufrufen will:
PHP:
$a = new File();
$a->file('name.txt');
Das führt aber leider, leider zu einem kleinen Fehler, der mir alles zerschießt. Hat jemand einen Vorschlag, wie man das regeln könnte, dass er es sowohl als auch akzeptiert? Oder vielleicht sogar eine bessere Lösung für diesen Lösungsansatz von mir. Das wäre wirklich toll.

Vielen Dank schon im Voraus!

PS: Bevor ich es vergesse - der Fehler sieht so aus:
Catchable fatal error: Object of class File could not be converted to string
 
Die Methode ist nichts besonderes:
PHP:
<?php
class File
 {
  public function file($file)
   {
    $this->temp['file'] = $file;
    return $this;
   }
  
  public function rename($name)
   {
    if(!rename($this->temp['file'], $name))
     return 'Could not rename "'.$this->temp['file'].'" to "'.$name.'"';
    
    return 'Rename "'.$this->temp['file'].'" to "'.$name.'"';
   }
 }
?>
 
Und wieder ist der Fehler der Fehler.
Catchable fatal error: Object of class File could not be converted to string

Was macht die Zeile?
PHP:
$a->file('name.txt');

Sie ruft eine Methode auf. Und was macht die Methode?
PHP:
public function file($file)
   {
    $this->temp['file'] = $file;
    return $this;
   }
Sie liefert das Objekt selbst.

Und wohin?
PHP:
$a->file('name.txt');

Ins Nirvana.
Das ist ungefähr so als würde mitten in einer Aufsatz von dir ein neuer Absatz anfangen und dort nur "Banane!" stehen und dann kommt schon der nächste Absatz. Da denkt sich PHP: Eine Banane?
 
an ZodiacXP: Das ist mir ja bewusst, die Frage war jetzt nur wie ich da Abhilfe schaffen kann. Also wie kann ich es so schreiben, dass es eben nicht die Klasse ins Nirwana schickt?

// EDIT: Habe das Problem selber gelöst. Ich musst nur die magische Funktion __toString() anwenden. Manchmal ist es wirklich einfacher als man denkt. Aber danke euch anderen, auch wenn ihr mir nicht besonders weiter geholfen habt. Thema geschlossen.
 
Zuletzt bearbeitet:
Kein Objekt o.ä. wiedergeben.
Oder Abfangen in eine Variable:
PHP:
$obj = $a->file("foo.ext");

Dazu könntest du auch noch den FilesystemIterator von PHP hinzuziehen:
http://de3.php.net/manual/en/class.filesystemiterator.php

Mehr geht grad net, muss weg ;)

EDIT:
auch wenn ihr mir nicht besonders weiter geholfen habt
:D Net meckern. Manchmal ist das Problem außerhalb vom PC.
Normalerweise macht man sowas mit zwei Klassen und/oder Vererbung.
 
Zuletzt bearbeitet:
Nur aus reiner Neugier. Der Fehler dürfte nur auftauchen, wenn du versuchst, die Rückgabe von File::file() per [phpf]echo[/phpf] oder ähnliches auszugeben. Ansonsten juckt es PHP herzlich wenig, was man mit dem Rückgabewert einer Methode/Funktion macht.
Das von dir implementierte "Verhalte" ist übrigens unter dem Namen Fluid Interfaces bekannt.
 
Bei mir spuckt der Interpreter (erwartungsgemäß) andere Fehler, denn da PHP in Bezug auf Funktions- und Methodennamen keine Character Case Unterscheidung macht, ist die file-Methode gleichzeitig Konstruktor (PHP4-Verhalten), und wird in deinem Beispiel ohne Argument aufgerufen. Das führt zu erwarteten Notices.

Die Fehlermeldung, die du erhälst, kann nur auf die Weise provoziert werden, wie es mAu beschreibt: Du möchtest ein Objekt, welches keine Methode __toString implementiert oder erbt, ausgeben. Den Fehlerursprung findest du ausnahmsweise am angegebenen Ort an der angegebenen Stelle (siehe Fehlermeldung, die du uns ohne Datei- und Zeilenbezug bereitgestellt hast). Das hat mit dem Fluent Interface Design nichts zu tun.
Es ist PHP sogar herzlich egal, ob eine Objektreferenz oder eine Variable leer im Raum steht:
PHP:
$a = 0;
$a;
Der einzige Knackpunkt daran, das Fluent Interface ins leere zurückzugeben ist der erforderliche Aufwand eine Referenz auf das Objekt zu erzeugen, welche dann ungenutzt im Raum hängt (und sofort wieder verworfen wird). Das wiederrum ist aber halb so kritisch, und wirft auch keinen Fehler.

Am reinen Klassendesign stört mich, dass du eine Datei auf eine eigenwillige Art und Weise abstrahierst.
PHP:
abstract class File {
	abstract public function __construct( $path );

	abstract public function getAbsolutePath();

	abstract public function exists();

	abstract public function isFile();
	abstract public function isDirectory();
	// oder File::getType() mit einer Flag-Rückgabe
	// zB File::TYPE_FILE, File::TYPE_DIRECTORY, File::TYPE_LINK, ...

	abstract public function copy( File $file );
	// alternativ copy( string $path ) o.ä.

	// ...
}

Du könntest ebenfalls auch splFileInfo oder das entsprechende splFileObject erweitern mit einer copy- oder move-Mothode, oder einen ganz anderen Weg gehen.

Deinen bisherigen Einsatz mit der Verwendung eines verborgenen Felds, welches nur im entsprechenden Kontext gültig ist, erscheint mir jedoch etwas heikel, vor allem dann, wenn später noch etwas geändert werden könnte.
 
Zurück