xploit Posted June 3, 2012 at 03:00 AM Report #459955 Posted June 3, 2012 at 03:00 AM (edited) Eu pretendo montar um sistema de hooks, semelhante ao do wordpress, mas estou com alguns problemas na programação/lógica, já consegui fazer com que este sistema dispare FUNCTIONS normalmente, mas não consigo fazer com que dispare METHODS dentro de uma CLASS. Código: <?php class Plugin { public static $actions = ""; function __construct() { } public static function add_action($hook,$function) { $hook=self::_hookname($hook); if(!self::exists_action($hook)) { self::$actions[$hook] = array(); } if(is_callable($function)) { self::$actions[$hook][] = $function; return TRUE; } } public static function do_action($hook,$params=NULL) { $hook=self::_hookname($hook); if(isset(self::$actions[$hook])) { foreach(self::$actions[$hook] as $function) { if(is_array($function) && is_object($function[0])) { call_user_func_array((array)$function, (array)$params); } elseif(is_array($params)) { call_user_func_array($function,$params); } else { call_user_func($function); } } return TRUE; } return FALSE; } public static function exists_action($hook) { return (isset(self::$actions[$hook]))? TRUE:FALSE; } private static function _hookname($hook) { return mb_strtolower($hook); } } /* * Classe de teste */ class testiCla{ function __construct() { echo "Disparou a class '".get_class(&$this)."' "; Plugin::add_action("init",array(&$this,"startup")); } public function startup() { echo "com a função ".__FUNCTION__."<br>"; } } /* * end */ /* * função de teste */ function testafuncao() { echo "Disparou a função '".__FUNCTION__."' <br>"; } /* * end */ /* * função de teste */ function load_da_classe() { echo "Disparou a função '".__FUNCTION__."' <br>"; global $claS; $claS= new testiCla(); } /* * end */ Plugin::add_action("init","testafuncao"); //Dispara a função "testafuncao()" Plugin::add_action("init","load_da_classe"); //Dispara a função "testafuncao()" Plugin::do_action("init"); // Faz o load do hook "init" ?> Edited June 3, 2012 at 06:58 PM by xploit
brunoais Posted June 3, 2012 at 12:30 PM Report #459977 Posted June 3, 2012 at 12:30 PM Não consigo ler o código. A indentação está demasiado complicada. Aconselho-te a corrigi-la para ficar legível. Acho que ninguém ir-te-á ajudar só com a informação que indicaste. Mesmo assim podes sempre dar uma vista de olhos aqui: http://php.net/manual/en/function.call-user-func.php "[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31 Life is a genetically transmitted disease, induced by sex, with death rate of 100%.
xploit Posted June 3, 2012 at 07:07 PM Author Report #460059 Posted June 3, 2012 at 07:07 PM Não consigo ler o código. A indentação está demasiado complicada. Aconselho-te a corrigi-la para ficar legível. Acho que ninguém ir-te-á ajudar só com a informação que indicaste. Mesmo assim podes sempre dar uma vista de olhos aqui: http://php.net/manua...l-user-func.php Não consigo entender o porquê de não estar exactamente como vejo aqui no DW e no bloco de notas, deve ser algum bug no editor do fórum quanto aos espaçamentos, porque aqui está bem legível, podes/podem fazer o download e abrir nos vossos editores secalhar é mais fácil para ler: http://www.2shared.com/file/yg6KWf7B/plugin.html Desde já obrigado pela ajuda brunoais, mas o meu problema não é em saber para que serve a função call_user_func, a principio até está bem empregue no código, a questão até será mais a lógica de perceber o porquê de quando tento chamar métodos dentro da classe, originados por um trigger ao sistema de hooks através de uma função, não ocorre nada, ou seja chama a função "load_da_classe()" mas não faz vir o resultado total causado por esta chamada entendes? É dificl explicar mas se copiares o código e olhares para ele vais perceber concerteza 🙂 Desde já obrigado pelas ajudas.
brunoais Posted June 4, 2012 at 12:13 PM Report #460246 Posted June 4, 2012 at 12:13 PM Desde já obrigado pela ajuda brunoais, mas o meu problema não é em saber para que serve a função call_user_func, a principio até está bem empregue no código, a questão até será mais a lógica de perceber o porquê de quando tento chamar métodos dentro da classe, originados por um trigger ao sistema de hooks através de uma função, não ocorre nada, ou seja chama a função "load_da_classe()" mas não faz vir o resultado total causado por esta chamada entendes? É dificl explicar mas se copiares o código e olhares para ele vais perceber concerteza 🙂 Desde já obrigado pelas ajudas. Experimentei o código e funciona. Bem... Há um erro no código (linha 78 e linha 79 estás a usar uma referencia para a chamada da função. O php n é assim) mas, fora isso, está sintaticamente e, possivelmente, logicamente correto. "[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31 Life is a genetically transmitted disease, induced by sex, with death rate of 100%.
xploit Posted June 4, 2012 at 01:29 PM Author Report #460263 Posted June 4, 2012 at 01:29 PM Experimentei o código e funciona. Bem... Há um erro no código (linha 78 e linha 79 estás a usar uma referencia para a chamada da função. O php n é assim) mas, fora isso, está sintaticamente e, possivelmente, logicamente correto. Mas consegues ver a chamada do método da class a ser executado? é que eu no meu webserver local não consigo, estou a correr o PHP 5.3. Ou seja a função "load_da_classe()" é chamada, depois dentro dessa função é criado o objecto " $claS= new testiCla();", dentro desta classe é executado a seguinte linha: "Plugin::add_action("init",array(&$this,"startup"));" Mas é aqui que está o problema, este método da classe não é disparado para o ecrã, dai eu dizer que algo está mal com isto, quando quero fazer hook de funções normais tudo bem... agora quando são hooks realizados dentro de classes simplesmente nada acontece, conseguiste entender o meu problema? Obrigado pela ajuda
xploit Posted June 5, 2012 at 07:03 AM Author Report #460440 Posted June 5, 2012 at 07:03 AM Depois de muitas horas a olhar para o código, já consegui resolver o problema, o problema é que era necessário criar um loop depois de cada execução de "do_action" e criar um histório de funções activas e as que ainda estavam desactivas, para depois nesse loop activar todas elas, as que ficaram para trás, é complicado de explicar, mas com este código podem criar um sistema de plugins usá-lo tanto em funções como dentro de classes a nível "multidimensional". Agora surgiu outra dúvida de lógica, imaginemos eu tenho a seguinte array: Array ( [init] => Array ( [0] => Array ( [active] => 1 [func] => load_da_classe [id] => 0 [priority] => 5 ), [1] => Array ( [active] => 1 [func] => load_da_classe_2 [id] => 0 [priority] => 2 ) ) Como é que eu faço para ordenar esta array pela chave "priority"? Eu queria que ela estivesse assim: Array ( [init] => Array ( [0] => Array ( [active] => 1 [func] => load_da_classe_2 [id] => 0 [priority] => 2 ), [1] => Array ( [active] => 1 [func] => load_da_classe [id] => 0 [priority] => 5 ) ) Ordenadas pela chave priority, luzes? 😛 Já agora deixo-vos aqui o código do sistema de hooks completo para funções standLone e para ser usado dentro de classes: (PS: a indentação está um pouco marada, mas isto tem haver com o editor quando faço copy/paste) class Plugin { public static $actions = array(); public static $pointer = 0; function __construct() { } public static function add_action($hook,$function,$priority=10) { $hook=self::_hookname($hook); if(!self::exists_action($hook)) { self::$actions[$hook] = array(); } if(is_callable($function)) { self::$actions[$hook][self::$pointer]["active"] = 0; self::$actions[$hook][self::$pointer]["func"] = $function; self::$actions[$hook][self::$pointer]["id"] = self::$pointer; self::$actions[$hook][self::$pointer]["priority"] = $priority; self::_order_actions($hook); self::$pointer++; return TRUE; } } public static function do_action($hook,$params=NULL) { $hook=self::_hookname($hook); if(isset(self::$actions[$hook])) { foreach(self::$actions[$hook] as $array=>$func) { if( self::$actions[$hook][$func["id"]]["active"]==0 ) { if(is_array($params)) { if(call_user_func_array($func["func"],$params)); self::$actions[$hook][$func["id"]]["active"]=1; } else { if(call_user_func($func["func"])) self::$actions[$hook][$func["id"]]["active"]=1; } } } foreach(self::$actions[$hook] as $array=>$func){ if($func["active"]==0) { return self::do_action($hook,$params); break; } } return TRUE; } return FALSE; } public static function exists_action($hook) { return (isset(self::$actions[$hook]))? TRUE:FALSE; } private static function _hookname($hook) { return mb_strtolower($hook); } private static function _order_actions($hook) { } } /* * Classe de teste */ class testiCla{ function __construct() { echo "Disparou a class '".get_class(&$this)."' "; Plugin::add_action("init",array($this,"startup")); } public function startup() { echo "com a função '".__FUNCTION__."' "; Plugin::add_action("init",array($this,"startup_2")); } public function startup_2($as) { echo "e também com a função '".__FUNCTION__."' com a passagem do argumento '$as'<br>"; } } /* * end */ /* * função de teste */ function testafuncao() { echo "Disparou a função '".__FUNCTION__."' <br>"; } /* * end */ /* * função de teste */ function load_da_classe() { echo "Disparou a função '".__FUNCTION__."' <br>"; global $claS; $claS= new testiCla(); } /* * end */ Plugin::add_action("init","load_da_classe"); //Dispara a função "testafuncao()" $parametro=25; Plugin::do_action("init",array($parametro)); // Faz o load do hook "init" com passagem de parâmetro
brunoais Posted June 5, 2012 at 08:00 AM Report #460448 Posted June 5, 2012 at 08:00 AM Vê isto: http://www.php.net/manual/en/function.usort.php Na função de callback é fácil, basta retornares a subtração entre os dois valores de priority. "[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31 Life is a genetically transmitted disease, induced by sex, with death rate of 100%.
xploit Posted June 5, 2012 at 08:06 AM Author Report #460450 Posted June 5, 2012 at 08:06 AM Vê isto: http://www.php.net/m...ction.usort.php Na função de callback é fácil, basta retornares a subtração entre os dois valores de priority. Obrigado mais uma vez brunoais, mas olha eu não estou a conseguir chegar lá, na parte lógica estou com um freeze na cabeça, poderias me dizer como faço isso com o usort?
Rui Carlos Posted June 5, 2012 at 05:10 PM Report #460616 Posted June 5, 2012 at 05:10 PM Penso que precisas de algo deste género: function compare($a, $b) { return $a['priority'] - $b['priority']; } usort($array, "compare"); Rui Carlos Gonçalves
xploit Posted June 5, 2012 at 07:38 PM Author Report #460672 Posted June 5, 2012 at 07:38 PM (edited) Penso que precisas de algo deste género: function compare($a, $b) { return $a['priority'] - $b['priority']; } usort($array, "compare"); Obrigado pela ajuda Rui Carlos, mas não funciona, ao executar não faz o pretendido que é ordenar o array pela chave "priority", ou seja é preciso que fique assim: Array ( [init] => Array ( [0] => Array ( [active] => 1 [func] => load_da_classe_2 [id] => 0 [priority] => 2 ), [1] => Array ( [active] => 1 [func] => load_da_classe [id] => 0 [priority] => 5 ) ) Edited June 5, 2012 at 07:39 PM by xploit
brunoais Posted June 5, 2012 at 09:43 PM Report #460729 Posted June 5, 2012 at 09:43 PM Já tentaste trocar o $a e o $b no que o Rui Carlos escreveu? "[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31 Life is a genetically transmitted disease, induced by sex, with death rate of 100%.
xploit Posted June 6, 2012 at 11:11 AM Author Report #460828 Posted June 6, 2012 at 11:11 AM Não dá também deixo vos aqui este mini código para verem como não ordena o arreio do maior ao mais pequeno pela chave priority: <?php $Array = array(); $Array["init"][0]["name"]="arr1"; $Array["init"][0]["priority"]=2; $Array["init"][1]["name"]="arr2"; $Array["init"][1]["priority"]=3; $Array["init"][2]["name"]="arr3"; $Array["init"][2]["priority"]=1; function compare($a, $b) { return $b['priority'] - $a['priority']; } usort($Array, "compare"); print_r($Array); ?>
Rui Carlos Posted June 6, 2012 at 11:34 AM Report #460830 Posted June 6, 2012 at 11:34 AM Acho que devia ser: usort($Array["init"], "compare"); Rui Carlos Gonçalves
xploit Posted June 6, 2012 at 12:01 PM Author Report #460843 Posted June 6, 2012 at 12:01 PM Está corretíssimo, muito obrigado Rui Carlos pela tua ajuda e obrigado ao brunoais, todos os problemas resolvidos 😉
xploit Posted June 6, 2012 at 02:46 PM Author Report #460905 Posted June 6, 2012 at 02:46 PM Entretanto surgiu outro problema lógico neste sistema, como pretendo ordenar as funções pela sua ordem de registo e pela sua ordem de prioridade deparei com o seguinte quebra-cabeças: Então vamos imaginar o seguinte cenário: Array criado Array ( [0] => Array ( [active] => 1 [func] => funcao_1 [id] => 0 [priority] => 10 ) [1] => Array ( [active] => 1 [func] => funcao_2 [id] => 1 [priority] => 10 ) [2] => Array ( [active] => 1 [func] => funcao_3 [id] => 2 [priority] => 1000 ) ) Agora eu pretendo ordenar este arreio pela chave "priority", mas sem tirar a ordenação dos que já lá estavam, seja que este arreio fique assim: Array ordenado por "priority" sem mexer na ordenação dos que lá estavam Array ( [0] => Array ( [active] => 1 [func] => funcao_3 [id] => 2 [priority] => 1000 ) [1] => Array ( [active] => 1 [func] => funcao_1 [id] => 0 [priority] => 10 ) [2] => Array ( [active] => 1 [func] => funcao_2 [id] => 1 [priority] => 10 ) ) Penso não ser necessário abrir um outro tópico, visto isto fazer parte do mesmo sistema, quando o acabar vou colocá-lo à disposição no forum. Obrigado pelas ajudas
Rui Carlos Posted June 6, 2012 at 02:59 PM Report #460920 Posted June 6, 2012 at 02:59 PM Precisas de um algoritmo de ordenação estável (que não é o caso do usort). Ou então podes ver se podes usar o id para definir a ordem (depende de como estás a atribuir o id aos elementos). function compare($a, $b) { $diff = $b['priority'] - $a['priority']; if($diff == 0) return $a['id'] - $b['id']; else return $diff; } Rui Carlos Gonçalves
xploit Posted June 6, 2012 at 04:05 PM Author Report #460957 Posted June 6, 2012 at 04:05 PM (edited) Precisas de um algoritmo de ordenação estável (que não é o caso do usort). Ou então podes ver se podes usar o id para definir a ordem (depende de como estás a atribuir o id aos elementos). function compare($a, $b) { $diff = $b['priority'] - $a['priority']; if($diff == 0) return $a['id'] - $b['id']; else return $diff; } Apliquei o teu código mas sem resultados, o resultado ficou igual não sei se estou a fazer algo mal, deixo aqui o código de forma mais simplificada para se poder mexer bem: /* Array ( [0] => Array ( [active] => 1 [func] => funcao_1 [id] => 0 [priority] => 10 ) [1] => Array ( [active] => 1 [func] => funcao_2 [id] => 1 [priority] => 10 ) [2] => Array ( [active] => 1 [func] => funcao_3 [id] => 2 [priority] => 1000 ) ) */ $Array[0]["active"] = 1; $Array[0]["func"] = "funcao_1"; $Array[0]["id"] = 0; // Este "id" é valor que está no index deste mesmo array, como o index é 0 o valor é 0. $Array[0]["priority"] = 10; $Array[1]["active"] = 1; $Array[1]["func"] = "funcao_2"; $Array[1]["id"] = 1; // Este "id" é valor que está no index deste mesmo array, como o index é 1 o valor é 1. $Array[1]["priority"] = 10; $Array[2]["active"] = 1; $Array[2]["func"] = "funcao_3"; $Array[2]["id"] = 2; // Este "id" é valor que está no index deste mesmo array, como o index é 2 o valor é 2. $Array[2]["priority"] = 1000; function OrdenaPriority($Array){ uasort($Array,function() { $diff = $b['priority'] - $a['priority']; if($diff == 0) return $a['id'] - $b['id']; else return $diff; }); print_r($Array); } OrdenaPriority($Array); Porque eu sinceramente não sei mesmo como criar esse algoritmo de ordenação, não sei a lógica a aplicar nisto : ( Edited June 6, 2012 at 04:08 PM by xploit
Rui Carlos Posted June 6, 2012 at 04:18 PM Report #460966 Posted June 6, 2012 at 04:18 PM Testa a função de comparação individualmente. (Em particular, com inputs que tenham a mesma prioridade.) Rui Carlos Gonçalves
xploit Posted June 6, 2012 at 04:23 PM Author Report #460975 Posted June 6, 2012 at 04:23 PM Como assim? Desculpa mas não entendi o que fazer.
xploit Posted June 6, 2012 at 04:34 PM Author Report #460984 Posted June 6, 2012 at 04:34 PM Acho que consegui resolver a ordenação do array com a função array_values(), pelo menos apresenta com a ordenação que pretendia. <?php /* Array ( [0] => Array ( [active] => 1 [func] => funcao_1 [id] => 0 [priority] => 10 ) [1] => Array ( [active] => 1 [func] => funcao_2 [id] => 1 [priority] => 10 ) [2] => Array ( [active] => 1 [func] => funcao_3 [id] => 2 [priority] => 1000 ) ) */ $Array[0]["active"] = 1; $Array[0]["func"] = "funcao_1"; $Array[0]["id"] = 0; // Este "id" é valor que está no index deste mesmo array, como o index é 0 o valor é 0. $Array[0]["priority"] = 10; $Array[1]["active"] = 1; $Array[1]["func"] = "funcao_2"; $Array[1]["id"] = 1; // Este "id" é valor que está no index deste mesmo array, como o index é 1 o valor é 1. $Array[1]["priority"] = 10; $Array[2]["active"] = 1; $Array[2]["func"] = "funcao_3"; $Array[2]["id"] = 2; // Este "id" é valor que está no index deste mesmo array, como o index é 2 o valor é 2. $Array[2]["priority"] = 1000; $Array[3]["active"] = 1; $Array[3]["func"] = "funcao_4"; $Array[3]["id"] = 2; // Este "id" é valor que está no index deste mesmo array, como o index é 2 o valor é 2. $Array[3]["priority"] = 950; function OrdenaPriority($Array){ uasort($Array,function() { $diff = $b['priority'] - $a['priority']; return $a['id'] - $b['id']; }); $Array = array_values($Array); echo "<br /><br />"; foreach($Array as $key=>$val){ echo $val["func"]."<br />"; } } OrdenaPriority($Array); ?> echo "<br /><br />"; foreach($Array as $key=>$val){ echo $val["func"]."<br />"; } } OrdenaPriority($Array); ?>
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now