PHP – co robić gdy musimy wymusić typy

Jak wiadomo PHPe nie jest językiem o silnym typowaniu. W wyniku tego do funkcji możemy przesyłać praktycznie wszystko. Często brak wstępnego określania typu parametrów w deskryptorze metod/funkcji pogarsza jakość i czytelność kodu. Osobiście czytając czyjś kod lubię wiedzieć co przyjmuje funkcja/metoda tzn. jaki konkretny typ parametrów one przyjmują. Dość często powstaje różnego rodzaju pomieszania typów, czyli wchodzi string potem przemieniany jest na inta a na wyjściu na dodatek możemy dostać obiekt… Ponadto w PHPe pomimo bogatej proceduralnej biblioteki do obsługi łańcuchów znaków nie istnieje jej wersja obiektowa, a szkoda… Z tego też względu pokusiłem opisać szkicowe rozwiązanie umożliwiające połączenie przyjemnego z pożytecznym tj. utworzenie klasy osłonowej na typ String ułatwiającej operację na obiektach tego typu. Rozwiązanie to daje:
1. Możliwość pośredniego rzutowania na dobrze zdefiniowany typ String
2. Możliwość sprawdzania typu String przez interpreter, tego czy przekazujemy prawidłowy parametr do funkcji/metody
3. Ustala konwencję w kodowaniu i aplikacji.
W miarę możliwość w następnych dniach postaram się opisać prezentowane rozwiązanie. Póki co ograniczę się do przedstawienia samego kodu.


_string = (string) $arg;
		}
		
		public function length() {
			return mb_strlen($this->_string);
		}
		
		public static function toString($arg) {
			return new String($arg);
		}
		
		public function getString()
		{
			return $this->_string;
		}
		
		public function setString($arg) {
			$this->_string = (string) $arg;
		}
		
		public function __toString() {
			return $this->_string;
		}
	}
}

/**
 * Przestrzeń nazw dla różnego rodzaju analizatorów.
 * 
 * @author Marcin M.
 *
 */
namespace AnalyzerBase {
	
	/**
	 * Abstarakcyjna klasa analizatora.
	 * 
	 * @author Marcin M.
	 *
	 */
	abstract class Analyzer {
		
	}
}

/**
 * Przestrzeń nazw dla analizatora Tekstu.
 * 
 * @author Marcin M.
 *
 */
namespace AnalyzerText {
	
	use AnalyzerBase;

	use String;
	
	/**
	 * Analizator tekstu
	 * 
	 * @author Marcin M.
	 *
	 */
	class Analyzer extends AnalyzerBase\Analyzer {
		
		/**
		 * Pobranie długości analizowanego tekstu przy wykorzystaniu klasy String
		 * 
		 * @tutorial Obiekty przekazywane są do funkcji i metod przez referencję
		 * 
		 * @param String\String $arg
		 * 
		 * @return int
		 */
		public function length(String\String $arg) {
			return (int) $arg->length();
		}
		
		/**
		 * Pobranie długości analizowanego tekstu przy wykorzystaniu klasy i mechanizmów Analizatora
		 * 
		 * @tutorial Obiekty przekazywane są do funkcji i metod przez referencję
		 * 
		 * @param String\String $arg
		 * 
		 * @return int
		 */
		public function size(String\String $arg) {
			return (int) mb_strlen($arg);
		}
		
		/**
		 * Tagowanie wybranych części tekstu
		 * 
		 * @param String\String $arg
		 * @param String\String $tag
		 * 
		 * @return void
		 */
		public function addTag(String\String $arg, String\String $tag) {
			$openTag = '<'.$tag.'>';
			$closeTag = '';
			
			$arg->setString($openTag.$arg->getString().$closeTag);
		}
	}
}

/**
 * Aplikacja z przypadkami testowymi
 */
namespace {

	$myString = new String\String('My default string');
	
	echo "Badany string to: " . 
		$myString;
	
	echo "\n";
	
	echo "Długośc badanego stringu to: " . 
		$myString->length();
	
	echo "\n";
	
	echo "Rzutowanie statyczne na typ string: " . 
		$myNewString = String\String::toString(567);
	
	echo "\n";
		
	echo "Badany rzutowany string to: " . 
		$myNewString;
	
	echo "\n";
	
	echo "Długośc badanego rzutownego stringu to: " . 
		$myNewString->length();
	
	echo "\n";
	
	$textAnalyzer = new AnalyzerText\Analyzer();
	
	echo 'Długośc analizowanego tekstu za pomocą Analyzer::length() to: ' . 
		$textAnalyzer->length($myString) . ' znaków';
	
	echo "\n";
	
	echo 'Długośc analizowanego tekstu za pomocą Analyzer::size() to: ' . 
		$textAnalyzer->size($myString) . ' znaków';
	
	echo "\n";
	
	echo 'Długośc analizowanego rzutowanego tekstu za pomocą Analyzer::length() to: ' . 
		$textAnalyzer->length($myNewString) . ' znaków';
	
	echo "\n";
	
	echo 'Długośc analizowanego rzutowanego tekstu za pomocą Analyzer::size() to: ' . 
		$textAnalyzer->size($myNewString) . ' znaków';
	
	echo "\n";
	
	echo 'Operacja przekazywanie obiektu typu String do analizy. Długośc tekstu to: ' . 
		$textAnalyzer->size(String\String::toString('Nowy string')) . ' ' . 
		$textAnalyzer->length(new String\String('Nowy string')) . ' ' .
		String\String::toString('Nowy string')->length();
	
	echo "\n";
	
	echo 'Test referencji: ';
	
	echo "\n";
	
	echo 'String przed zmianą: '.
		$noTag = new String\String('Jestem stringiem bez tagu na końcu');
		
	echo "\n";
	
	echo $noTag;
	
	echo "\n";
	
	echo 'String po zmianeie dodanie tagu `koniec_zdania`: ';
	
	$textAnalyzer->addTag($noTag, String\String::toString('koniec_zdania'));
	
	echo "\n";
	
	echo $noTag;
	
	echo "\n";
	
	echo 'Operacja nie powiedzie się, musimy dysponować obiektem typu String ' . 
		$textAnalyzer->size('Nowy string') . ' ' . 
		$textAnalyzer->length('Nowy string');
	
	echo "\n";
	
}
?>

Skomentuj ten wpis