Jump to content

Recommended Posts

Posted (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 by xploit
Posted

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%.

Posted

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.

Posted

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%.

Posted

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

Posted

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
Posted

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%.

Posted (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 by xploit
Posted

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%.

Posted

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);
?>
Posted

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

Posted

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;
}
Posted (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 by xploit
Posted

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);


?>

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.