Some of posts from this blog has been moved to dywicki.pl. You will be automatically redirected to new blog if you would submit comment.
New posts are published on dywicki.pl, this blog contains old content and it is not continued.

Niektóre posty z tego bloga zostały przeniesione do dywicki.pl. Zostaniesz automatycznie przekierowany jeśli bedzięsz chciał dodać komentarz.
Nowe posty sa publikowane na dywicki.pl, ten blog zawiera stare treści i nie jest kontynuowany.

Adnotacje w Javie i w PHP

Filed under Java,PHP by

Parę dni wstecz trafiłem na ciekawe rozszerzenie Reflection API do PHP. Umożliwia ono używanie tagów phpdoc w charakterze adnotacji. Rozwiązanie te jest zbliżone do znanego mi z Javy xdocleta. Drobną, aczkolwiek zauważalną, różnicą jest fakt, że xdoclet był odpalany przed kompilacją kodu ponieważ bytecode nie zawierał adnotacji. Oczywiście po wejściu Javy 5 xdoclet podupadł, jako coś co wyparły właśnie adnotacje. Może dla tych, którzy nie mieli okazji spotkania sie z takim rozwiązaniem drobny przykład kodu w Javie:

package pl.dywicki.swe.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity(name = "user")
@Table(name = "user", schema = "public")
public class User {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "user_id")
	private long id;
    
	@Column(name="user_login")
	private String login;

	@Column(name="user_password")
	private String password;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
	
}

Co umożliwia takie rozwiązanie? Przede wszystkim dzięki zastosowaniu adnotacji spada ilość dodatkowych plików zawierających konfiguracje i mapowania. Oczywiście nie da się ich dzięki temu rozwiązaniu wykluczyć zupełnie, aczkolwiek da się znacznie ograniczyć ich użycie. Wielką zaletą, o której do tej pory nie wspomniałem, w przypadku Javy, jest to, że adnotacje możemy odczytywać w czasie uruchamiania programu a nie przed jego kompilacją.

Adnotacja od strony technicznej

Jak można zadeklarować własną adnotację? Służy do tego specjalna konstrukcja:

public @interface Name {
   String value() default "anonymous";
}

Użycie takiej adnotacji:

@Name // poprawnie
public class Component {}

@Name("user.session") // również poprawnie
public class User {}

Możemy również przekazać kilka wartości gdy zadeklarujemy w adnotacji odpowiednie pole:

public @interface Relation {
   String[] belongsTo();
   String offer();
}

Użycie takiej adnotacji:

@Relation(belongTo = {"users", "groups"}, offer = "privileges")
public class PrivilegesEntityMapping {}

Warto tutaj wspomnieć o dwóch magicznych umowach. Po pierwsze atrybut o nazwie value jest domyślnym przypisaniem wartości podanej w nawiasach. Tzn przy wywołaniu @Name(“user.session”) możemy pobrać atrybut poprzez annotationInstance.value(). Po drugie dodanie po nazwie pola default “wartość” pozwala na pominięcie atrybutu przy definicji. Z ograniczeń, jakie mają adnotacje w Javie – wartościami atrybutów mogą być ciągi znaków, typy (klasy) oraz typy wyliczeniowe (enumy).

Jak użyć adnotacji? Korzystając z reflection api.

Name instance = getClass().getAnnotation(Name.class); // Name.class to typ naszej adnotacji.
System.out.println(instance.value());

Adnotacje a PHP

Jak wcześniej wspominałem, adnotacje nie są elementem PHP, chociaż ludzie pokusili się już o zbudowanie mechanizmu podobnego do tego, który jest w Javie. Jednym z takich projektów jest Addendum. Warto zaznaczyć, że nie jest to nazwa wyssana z palca a słowo “addendum” ma swoje znaczenie również w języku polskim i ogólnie rzecz biorąc znaczy dodatek do jakiegoś tekstu (więcej informacji na wikisłowniku).

Jak wygląda użycie adnotacji w PHP? Jednym z przykładów może być Torpedeo. Projekt tego samego autora co Addendum, będący implementacją lekkiego ORMa. Przykładowa deklaracja obsługiwana przez Torpedeo:

<?php
/**
 * @Table('nodes')
 */
class Node {
	/** @Integer */
	public $id;
	
	/** @String */
	public $title;
	
	/**
	 * @Integer
	 * @Nullable
	 * @Column('parent_id');
	 */
	public $parentId;
	
	/** @Boolean */
	public $visible;
}
?>

Addendum wymaga by klasy adnotacji rozszerzały klasę Annotation:

<?php
class Nullable extends Annotation {}
class Transient extends Annotation {}
?>

Dodatkowo biblioteka dostarcza rozszerzeń reflection API z PHP5 umożliwiające odczytywanie adnotacji. Dokładny tutorial jak używać tego narzędzia można znaleźć na oficjalnej stronie projektu.

Adnotacje w PHP?

Pytanie czy adnotacje w PHP przyjmą się tak samo dobrze jak w Javie? Zdaje się, że by o tym mówić jest zbyt wcześnie, ponieważ projektów, które korzystają z tego mechanizmu jest na chwilę obecną bardzo mało. Sądząc jednak po tym jak szybko rozwinął się xdoclet można twierdzić, że to tylko kwestia czasu. Chociaż.. może w Javie po prostu jest więcej plików konfiguracyjnych?

10 responses so far

10 Responses to “Adnotacje w Javie i w PHP”

  1. Murwazy says:

    ezpdo tego uzywa
    http://www.ezpdo.net/blog/?p=5

    ja wykorzystuje adnotacje do oznaczania klas i metod majacych podlegac kontroli dostepu, takze opisy metod wyciagam w ten sposob.

    bardzo fajna sprawa

  2. Tak, zauważyłem to jakiś czas temu, co spowodowało z mojej strony większe zainteresowanie ezpdo. Jakkolwiek nie jest to “standardowa” adnotacja w rozumieniu Javy a raczej znacznik xdocletowy. Parząc np na kod z ezpdo:

    /* @orm has many Book*/
    

    Wydaje mi się to dosyć karkołomne. W jaki sposób przekazać wiecej informacji na temat relacji? Nie zauważyłem przykładu w którym któraś z klas miałaby dwa razy tag @orm. :) Wygodniejsze zdaje się oznaczanie chociażby kategorią:

    /* @orm.manyToMany Book
     * @orm.collection type=set synchronized=true
     */
    

    W JPA wygląda to mniej więcej tak:

    @Entity
    class Question {
        // tutaj jakieś nieznaczące atrybuty
        @ManyToOne(optional=false) 
        @JoinColumn(name="exam_id", nullable=false) // nazwa kolumny w encji Exam
        private Exam exam;
    }
    
    @Entity
    @Table(name = "exams")
    class Exam {
        // mappedBy to nazwa property w którym jest zachowane powiązanie z egzaminem
        @OneToMany(targetEntity=Question.class, mappedBy = "exam")
        @OrderBy("order") // property encji Question które będzie użyte do posortowania
        private List[Question] questions = new ArrayList[Question]();
    }
  3. Murwazy says:

    hm, wszystko sie da zrobic, to kwestia napisania parsera. fakt ze troche malo wygodne sie to robi.

    imho relacje lepiej definiowac jednak inaczej, ezpdo nie rozwija sie od jakiegos czasu niestety. ze swojej strony nieustannie polecam doctrine.

    adnotacje sa jednak szalenie uzyteczne w wielu przypadkach, mozna sobie zdefiniowac tyle tagow ile potrzebujemy i bardzo to ulatwia prace.

    orm to jakby inna sprawa ale np acl z wykorzystaniem refleksji i adnotacji rowna sie pelna automatyka. piszac kod mamy automatycznie dostepne w panelu wybrane przez nas metody wraz z opisem.

  4. Myślę, że za jakiś czas zabiorę się za pisanie orm-a dla PHP, który będzie wspierał adnotacje. Chciałbym by nie był on kopią już istniejącego rozwiązania (Propel, Doctrine, ez pdo) a alternatywą pełną gembą. To, co mi się np najbardziej podoba w Doctrine to query language (przypomina ten, znane mi z Hibernate), z ez pdo wziąłbym adnotacje, z propela logiczną strukturę (np organizację w “platformy”). Jednym z głownych celów jest to by ORM był całkowicie przeźroczysty (żadnego wymuszonego dziedziczenia).

    Postawiony jest już trac, są jakieś zaczątki kodu, póki co niezwiązanego z ORMem jako tako. Kod dokumentowany w języku angielskim, dokumentacja raczej w polskim. Jak tylko ogarnę się z sesją zacznę publikować raporty. ;)

    Nazwa kodowa projektu to storm!

  5. Ace says:

    Hmmm… Bawić się w kolejny ORM? Czy to nie jest wyważanie otwartych drzwi?

  6. Ace Wiesz przecież jak korzysta się z Propela. Ja wiem, że można coś takiego napisać lepiej.

  7. murwazy says:

    hm, nowy orm pisany od podstaw?

    imo lepiej dolacz do teamu rozwijajacego doctrine, szkoda ze zend nie zdecydowal sie na wlaczenie tego projektu do frameworka.

    definiowanie relacji za pomoca adnotacji nie jest moim zdaniem tak wygodne jak rozwiazanie uzyte w doctrine.
    co jak co ale doctrine jest bardzo czytelne i proste do stosowania.

    tak czy owak – powodzenia :)

  8. Sędziwój says:

    To już wiem skąd Ace wie o doctrine…
    Nie wiem jak dla mnie konfiguracja Propela jest bardziej wygodna, ale to na oko, skoro mówicie że doctrine jest ciekawy, to go spróbuję jak znajdę czas, ale nie wydaje mi się aby to zmieniło moją opinię.
    Bo wydaje mi się wygodniejsze zdefiniowanie XML i wygenerowanie kodu niż tłuczenie się z kodem i dawaniem adnotacji.
    (hm, muszę się przyjrzeć, i zobaczyć jak realizowane są adnotacje w PHP, bo chyba nie wpływają negatywnie na wydajność?)

  9. johno says:

    Hi, my Polish friends. I’ve just wanted to say thanks for looking at and linking Addendum annotations project. I have some difficulties reading Polish (I am from Slovakia) but yesterday I’ve just updated Addendum with new features and am looking for some projects/frameworks that would like to uses Annotations.

  10. Thanks for you comment johno, I would like to use Addendum in my small project – that would be ORM library. But currently I haven’t free time to do anything. I am sure – in future i’ll use annotations support in PHP.

Leave a Reply

You must be logged in to post a comment.